Repository: reposaur/reposaur
Branch: main
Commit: ba8af4048815
Files: 42
Total size: 117.1 KB
Directory structure:
gitextract_j1gkgj0k/
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.yml
│ │ ├── config.yml
│ │ └── feature_request.yml
│ ├── codeowners
│ ├── dependabot.yml
│ └── workflows/
│ └── test.yml
├── .gitignore
├── .goreleaser.yml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── Taskfile.yaml
├── action.yml
├── cmd/
│ └── rsr/
│ ├── internal/
│ │ ├── bundle/
│ │ │ └── bundle.go
│ │ ├── cmdutil/
│ │ │ ├── env.go
│ │ │ ├── flag.go
│ │ │ ├── io.go
│ │ │ └── logger.go
│ │ ├── exec/
│ │ │ └── exec.go
│ │ ├── root/
│ │ │ └── root.go
│ │ └── test/
│ │ └── test.go
│ └── rsr.go
├── go.mod
├── go.sum
├── install.sh
├── internal/
│ ├── build/
│ │ └── build.go
│ └── policy/
│ ├── engine.go
│ └── errors.go
├── pkg/
│ ├── output/
│ │ ├── report.go
│ │ └── sarif.go
│ └── sdk/
│ └── sdk.go
├── provider/
│ ├── github/
│ │ ├── client/
│ │ │ └── client.go
│ │ ├── github.go
│ │ ├── github_test.go
│ │ └── internal/
│ │ └── builtin/
│ │ ├── graphql.go
│ │ ├── request.go
│ │ └── response.go
│ ├── provider.go
│ └── provider_test.go
└── scripts/
└── completions.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/FUNDING.yml
================================================
github: [reposaur, crqra]
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: Bug Report
description: File a bug report
title: "[Bug]: "
labels: ["bug", "triage"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report and improving Reposaur!
- type: textarea
id: description
attributes:
label: Description
description: Describe what happened
placeholder: Tell us what you see!
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expectation
description: Describe what you expected to have happened
placeholder: Tell us what you expected to see!
validations:
required: true
- type: input
id: version
attributes:
label: Version
description: What's the version of Reposaur you're running?
placeholder: 0.0.0
- type: textarea
id: logs
attributes:
label: Relevant log output
description: |
Please copy and paste any relevant log output.
This will be automatically formatted into code, so no need for backticks.
render: shell
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: |
By submitting this issue, you agree to follow our
[Code of Conduct](https://github.com/reposaur/reposaur/blob/main/CODE_OF_CONDUCT.md)
options:
- label: I agree to follow Reposaur's Code of Conduct
required: true
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: true
contact_links:
- name: Ask a question
url: https://github.com/orgs/reposaur/discussions
about: Community Support Forum
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.yml
================================================
name: Feature Request
description: Suggest a new idea or feature to add to Reposaur
title: "[Feature]: "
labels: ["enhancement", "triage"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to suggest new ideas and features,
improving Reposaur!
- type: textarea
id: description
attributes:
label: What would you like to see improved?
description: |
Is there something challenging or frustrating about Reposaur
that you're trying to improve? How would this improvement make your
experience better?
validations:
required: true
- type: textarea
id: ideal-solution
attributes:
label: What would be the ideal solution?
validations:
required: true
- type: textarea
id: good-solution
attributes:
label: What would be a \"good enough\" solution?
validations:
required: true
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: |
By submitting this issue, you agree to follow our
[Code of Conduct](https://github.com/reposaur/reposaur/blob/main/CODE_OF_CONDUCT.md)
options:
- label: I agree to follow Reposaur's Code of Conduct
required: true
================================================
FILE: .github/codeowners
================================================
* @crqra
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"
================================================
FILE: .github/workflows/test.yml
================================================
name: Test
on:
push:
branches:
- main
pull_request:
env:
GO111MODULE: on
jobs:
golangci-lint:
name: Golang CI Lint
runs-on: ubuntu-latest
steps:
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: "1.18"
- name: Checkout
uses: actions/checkout@v3
- name: Golang CI Lint
uses: golangci/golangci-lint-action@v3.1.0
with:
version: latest
args: --verbose
test-unix:
strategy:
fail-fast: false
matrix:
platform:
- ubuntu
- macOS
go:
- 18
name: "${{ matrix.platform }} | 1.${{ matrix.go }}.x"
runs-on: ${{ matrix.platform }}-latest
steps:
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.${{ matrix.go }}.x
- name: Checkout
uses: actions/checkout@v3
- name: Setup Cache
uses: actions/cache@v3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-1.${{ matrix.go }}.x-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-1.${{ matrix.go }}.x-
- name: Test
run: go test ./...
test-win:
name: MINGW64
defaults:
run:
shell: msys2 {0}
runs-on: windows-latest
steps:
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
update: true
install: >
git
make
unzip
mingw-w64-x86_64-go
- name: Checkout
uses: actions/checkout@v3
- name: Setup Cache
uses: actions/cache@v3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-${{ matrix.go }}-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-${{ matrix.go }}-
- name: Test
run: go test ./...
================================================
FILE: .gitignore
================================================
# Used for local tests only
/config.yaml
/policy/
/testdata/events/_*.json
dist/
bin/
# Generated
/completions
# Editors
/.idea
/.vscode
/.fleet
================================================
FILE: .goreleaser.yml
================================================
before:
hooks:
- go mod tidy
- go vet ./...
- ./scripts/completions.sh
builds:
- id: rsr
binary: rsr
main: ./cmd/rsr/rsr.go
ldflags:
- -s -w -X github.com/reposaur/reposaur/internal/build.Version={{.Version}}
env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
- id: reposaur
binary: reposaur
main: ./cmd/rsr/rsr.go
ldflags:
- -s -w -X github.com/reposaur/reposaur/internal/build.Version={{.Version}}
env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
archives:
- replacements:
darwin: Darwin
linux: Linux
windows: Windows
386: i386
amd64: x86_64
format_overrides:
- goos: windows
format: zip
files:
- README.md
- LICENSE
- completions/*
checksum:
name_template: "checksums.txt"
snapshot:
name_template: "{{ incpatch .Version }}-next"
changelog:
use: github
sort: asc
filters:
exclude:
- "^test:"
- "^chore:"
- "^build:"
groups:
- title: 'New Features and updates'
regexp: "^.*feat[(\\w)]*:+.*$"
order: 0
- title: 'Bug fixes'
regexp: "^.*fix[(\\w)]*:+.*$"
order: 10
- title: 'Documentation updates'
regexp: "^.*docs[(\\w)]*:+.*$"
order: 20
- title: Other work
order: 999
release:
github:
owner: reposaur
name: reposaur
prerelease: auto
footer: |
**Full Changelog**: https://github.com/reposaur/reposaur/compare/{{ .PreviousTag }}...{{ .Tag }}
## What to do next?
- Read the [documentation](https://docs.reposaur.com)
- Join our [Slack](https://slack.reposaur.com)
- Follow us on [Twitter](https://twitter.com/reposaurhq)
brews:
- tap:
owner: reposaur
name: homebrew-tap
commit_author:
name: goreleaserbot
email: goreleaser@carlosbecker.com
commit_msg_template: "chore: brew formula update for {{ .ProjectName }} version {{ .Tag }}"
folder: Formula
homepage: "https://reposaur.com"
description: "Open source compliance tool for development platforms"
license: "MIT"
test: |
system "#{bin}/rsr"
install: |-
bin.install "rsr"
bash_completion.install "completions/rsr.bash" => "rsr"
zsh_completion.install "completions/rsr.zsh" => "_rsr"
fish_completion.install "completions/rsr.fish"
nfpms:
- vendor: Reposaur
homepage: https://reposaur.com/
maintainer: João Cerqueira <oss@cerqueira.io>
description: |-
The open source compliance tool for development platforms.
license: MIT
contents:
- src: ./completions/rsr.bash
dst: /usr/share/bash-completion/completions/rsr
file_info:
mode: 0644
- src: ./completions/rsr.fish
dst: /usr/share/fish/completions/rsr.fish
file_info:
mode: 0644
- src: ./completions/rsr.zsh
dst: /usr/share/zsh/vendor-completions/_rsr
file_info:
mode: 0644
- src: ./LICENSE
dst: /usr/share/doc/rsr/copyright
file_info:
mode: 0644
formats:
- apk
- deb
- rpm
section: utils
priority: extra
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
oss@cerqueira.io.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
Beforehand, thank you for considering contributing to Reposaur! We welcome and
appreciate any help we can get.
Contributors are expected to follow our [Code of Conduct](CODE_OF_CONDUCT.md).
## Feedback and Questions
We appreciate any feedback we can get and are happy to answer any questions you
might have!
Reach out to us in [Discussions][discussions] or in our [Slack Workspace][slack].
## Bug Reporting and Feature Requests
### Bug Reports
If you've found an issue in the CLI, SDK or Policy Engine, please
[open a bug report][bug-report]. We appreciate the feedback and will try to help
as soon as possible. The form will guide you on how to report the bug.
### Feature Requests
If you've an exiting idea, new use case or anything else, we'd love to hear it!
Please, [open a feature request][feature-request] and share it with the community!
The form will guide you on how to request a new feature.
## Development
To get your development environment ready you'll need to have the following
installed:
- [Go][go] >= 1.18
- [Task][task] >= 3.0
### Setting up
Fork the repository to your account and clone it to your machine. Build for the
first time and make sure everything is working as expected:
```console
$ task build
```
If you don't have Task installed you can issue the following commands:
```console
go mod tidy
go build -o ./.bin/rsr ./cmd/rsr/rsr.go \
-ldflags "-s -w -X github.com/reposaur/reposaur/internal/build.Version=devel"
```
After the command above you should have `rsr` available in `./.bin`:
```console
$ ./.bin/rsr --version
rsr version devel
```
Happy coding!
### Creating a Pull Request
We don't have any rigid structure for Pull Requests right now, although that's
expected to change in the future.
For now, just explain briefly what your changes address and link any related
issues or other Pull Requests.
Creating an [issue][issues] prior to the Pull Request is highly recommended to
avoid multiple people working on the same issue, resulting in duplicated effort.
Visit the [Pull Requests][pulls] page.
## Releasing
To create new releases you'll need to have the following tools installed:
- [GoReleaser][goreleaser] >= 1.9
- [svu][svu] >= 1.9
[discussions]: https://github.com/orgs/reposaur/discussions
[issues]: https://github.com/reposaur/reposaur/issues
[pulls]: https://github.com/reposaur/reposaur/pulls
[bug-report]: https://github.com/reposaur/reposaur/issues/new?assignees=&labels=bug%2Ctriage&template=bug_report.yml&title=%5BBug%5D%3A+
[feature-request]: https://github.com/reposaur/reposaur/issues/new?assignees=&labels=enhancement%2Ctriage&template=feature_request.yml&title=%5BFeature%5D%3A+
[slack]: https://slack.reposaur.com
[go]: https://go.dev/
[task]: https://taskfile.dev/
[goreleaser]: https://goreleaser.com
[svu]: https://github.com/caarlos0/svu
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2022 João Cerqueira and Reposaur contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
<div align="center">
[![logo][logo]][website]
# Reposaur
[![go-report][go-report-badge]][go-report]
[![tests-workflow][tests-workflow-badge]][tests-workflow]
[![license][license-badge]]()
[![discussions][discussions-badge]][discussions]
[![discord][discord-badge]][discord-invite]
[![twitter][twitter-badge]][twitter]
**Reposaur is the open source compliance tool for development platforms.**
Audit, verify and report on your data and configurations easily with pre-defined and/or custom policies. <br />
Supports GitHub. GitLab, BitBucket and Gitea support soon.
⚠️ before 1.0.0 expect some bugs and API changes ⚠️
[Getting started](#getting-started) •
[Installation](#installation) •
[Documentation][docs] •
[Guides](#guides) •
[Integrations](#integrations)
</div>
# Getting Started
Have you ever felt like you don't know what's happening in your GitHub/GitLab/BitBucket repositories? Between 100s or 1000s of them it's hard to make sure every single one is compliant to certain security and best practices guidelines.
Reposaur is here to fix that, empowering you to focus on your work instead of hunting for issues and misconfigurations.
## Features
- Custom policies using the [Rego][rego] policy language ([learn more][docs-policy])
- A simple, composable and easy-to-use CLI ([learn more][docs-cli])
- Extendable using a straightforward SDK (written in Go)
- Reports follow the standard SARIF format, enabling easy integrations with different systems
- Policies can be unit tested, guaranteeing they work as expected
- Integration with the major development platforms (see [Integrations](#integrations))
- Easily integrate new platforms using the SDK
## Guides
- [Writing your first policy](https://docs.reposaur.com/guides/writing-your-first-policy)
# Installation
#### Homebrew Tap
```shell
$ brew install reposaur/tap/reposaur
```
#### DEB, RPM and APK Packages
Download the `.deb`, `.rpm` or `.apk` packages from the [releases page][releases]
and install them with the appropriate tools.
#### Go
```shell
$ go install github.com/reposaur/reposaur/cmd/rsr@latest
```
#### Script
The script will download the latest release to a temporary directory and decompress
it to `$HOME/.reposaur`.
```shell
$ curl -sfL https://get.reposaur.com | bash
```
# Integrations
| Platform | Status | Details |
|------------------------|-------------|-------------------------------------------------------------------------------------------|
| [GitHub][github] | In progress | [Provider][github-provider] • [GitHub App][github-app] • [GitHub Actions][github-actions] |
| [GitLab][gitlab] | Planned | N/A |
| [Gitea][gitea] | Planned | N/A |
| [BitBucket][bitbucket] | Not planned | N/A |
# Contributing
We appreciate every contribution, thanks for considering it!
**TLDR;**
- [Open an issue][issues] if you have a problem or found a bug
- [Open a Pull Request][pulls] if you have a suggestion, improvement or bug fix
- [Open a Discussion][discussions] if you have questions or want to discuss ideas
Check our [Contributing Guide](CONTRIBUTING.md) for more detailed information.
# License
This project is released under the [MIT License](LICENSE).
[website]: https://reposaur.com
[docs]: https://docs.reposaur.com
[docs-policy]: https://docs.reposaur.com/policy
[docs-cli]: https://docs.reposaur.com/cli/exec
[issues]: https://github.com/reposaur/reposaur/issues
[pulls]: https://github.com/reposaur/reposaur/pulls
[logo]: https://user-images.githubusercontent.com/8532541/169531963-bafd3cbf-dadd-486d-83cc-10a4d39c1dbc.png
[rego]: https://www.openpolicyagent.org/docs/latest/policy-language/
[license]: https://github.com/reposaur/reposaur/blob/main/LICENSE
[license-badge]: https://img.shields.io/github/license/reposaur/reposaur?style=flat-square&color=blueviolet
[go-report]: https://goreportcard.com/report/github.com/reposaur/reposaur
[go-report-badge]: https://goreportcard.com/badge/github.com/reposaur/reposaur?style=flat-square&color=blueviolet
[tests-workflow]: https://github.com/reposaur/reposaur/actions/workflows/test.yml
[tests-workflow-badge]: https://img.shields.io/github/workflow/status/reposaur/reposaur/Test?label=tests&style=flat-square
[discussions]: https://github.com/orgs/reposaur/discussions
[discussions-badge]: https://img.shields.io/github/discussions/reposaur/reposaur?style=flat-square&color=blueviolet
[discord-invite]: https://discord.gg/jpx4sqkQYY
[discord-badge]: https://img.shields.io/discord/1021712577132240898?label=discord&style=flat-square&color=blueviolet
[twitter]: https://twitter.com/reposaurhq
[twitter-badge]: https://img.shields.io/badge/twitter-%40reposaurhq-blueviolet?style=flat-square
[github]: https://github.com
[github-app]: https://docs.reposaur.com/integrations/github-app
[github-actions]: https://docs.reposaur.com/integrations/github-actions/setup-reposaur
[github-provider]: https://docs.reposaur.com/
[gitlab]: https://gitlab.com
[gitea]: https://gitea.io
[bitbucket]: https://bitbucket.org
[releases]: https://github.com/reposaur/reposaur/releases/latest
================================================
FILE: Taskfile.yaml
================================================
# https://taskfile.dev
version: "3"
tasks:
deps:
run: once
cmds:
- go mod tidy
silent: true
build:
deps: [deps]
vars:
VERSION: devel
cmds:
- go build -ldflags "-s -w -X github.com/reposaur/reposaur/internal/build.Version={{.VERSION}}" -o ./bin/rsr ./cmd/rsr/rsr.go
silent: true
release:
vars:
VERSION:
sh: "[ '{{.VERSION}}' != '' ] && echo '{{.VERSION}}' || svu"
cmds:
- git checkout main
- git tag {{.VERSION}}
- git push --tags
- goreleaser --rm-dist
- defer: rm -rf dist
silent: true
unreleased:
desc: Prints the commits between main branch and latest version
vars:
VERSION:
sh: "[ '{{.VERSION}}' != '' ] && echo '{{.VERSION}}' || curl -s https://api.github.com/repos/reposaur/reposaur/releases/latest | jq -r '.tag_name'"
cmds:
- git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit main...{{.VERSION}}
silent: true
================================================
FILE: action.yml
================================================
name: Reposaur
author: Reposaur Authors
description: Audit your GitHub data using custom policies written in Rego
branding:
icon: lock
color: purple
inputs:
version:
description: Version
default: main
required: false
runs:
using: composite
steps:
- run: |
curl -o- https://raw.githubusercontent.com/reposaur/reposaur/${{ inputs.version }}/install.sh | bash
echo "${{ github.action_path }}" >> $GITHUB_PATH
working-directory: ${{ github.action_path }}
shell: bash
================================================
FILE: cmd/rsr/internal/bundle/bundle.go
================================================
package bundle
import (
"os"
"github.com/reposaur/reposaur/cmd/rsr/internal/cmdutil"
"github.com/reposaur/reposaur/pkg/sdk"
"github.com/rs/zerolog"
"github.com/spf13/cobra"
)
type bundleParams struct {
policyPaths []string
experimental bool
}
func NewCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "bundle [-p POLICY_PATH...] <OUTPUT>",
Short: "Creates a bundle from the policies at POLICY_PATH (experimental)",
Long: "Creates a bundle from the policies at POLICY_PATH (experimental)",
}
var (
params = &bundleParams{}
flags = cmd.Flags()
)
cmdutil.AddPolicyPathsFlag(flags, ¶ms.policyPaths)
cmdutil.AddExperimentalFlag(flags, ¶ms.experimental)
cmd.Run = func(cmd *cobra.Command, args []string) {
var (
ctx = cmd.Context()
logger = zerolog.Ctx(ctx)
)
if !params.experimental {
logger.Fatal().Msg("experimental feature, please use --experimental to accept")
}
if len(args) != 1 {
logger.Fatal().Msgf("exactly 1 arguments required, got %d", len(args))
}
rsr, err := sdk.New(ctx, params.policyPaths, sdk.WithLogger(*logger))
if err != nil {
logger.Fatal().Err(err).Msg("could not instantiate SDK")
}
out, err := os.OpenFile(args[0], os.O_WRONLY+os.O_CREATE+os.O_TRUNC, 0o666)
if err != nil {
logger.Fatal().Err(err).Msg("could not open file")
}
err = rsr.Bundle(ctx, params.policyPaths, out)
if err != nil {
logger.Fatal().Err(err).Msg("could not create bundle")
}
logger.Info().Msgf("bundle written to %s", args[0])
}
return cmd
}
================================================
FILE: cmd/rsr/internal/cmdutil/env.go
================================================
package cmdutil
import (
"fmt"
"os"
"strconv"
)
// getEnv looks up every key in keys in the environment variables and returns
// the first value found. If no value is found, returns an empty string.
func getEnv(keys ...string) string {
for _, k := range keys {
if v := os.Getenv(k); v != "" {
return v
}
}
return ""
}
// getInt64Env is similar to getEnv but converts the value to an int64. If no
// value is found returns the zero-value for int64.
func getInt64Env(keys ...string) int64 {
val := getEnv(keys...)
if val == "" {
return 0
}
intVal, err := strconv.ParseInt(val, 10, 0)
if err != nil {
panic(fmt.Errorf("failed parsing env variable to int64: %w", err))
}
return intVal
}
================================================
FILE: cmd/rsr/internal/cmdutil/flag.go
================================================
package cmdutil
import (
githubclient "github.com/reposaur/reposaur/provider/github/client"
"github.com/spf13/pflag"
)
type GitHubClientOptions struct {
// GitHub API Base URL
BaseURL string
// GitHub Personal Access Token
Token string
// GitHub App ID
AppID int64
// GitHub App Private Key
AppPrivateKey string
// GitHub App Installation ID
InstallationID int64
}
func AddPolicyPathsFlag(flags *pflag.FlagSet, p *[]string) {
flags.StringSliceVarP(p, "policy", "p", []string{"."}, "path to policy files or directories")
}
func AddOutputFlag(flags *pflag.FlagSet, p *string) {
flags.StringVarP(p, "output", "o", "-", "output filename")
}
func AddTraceFlag(flags *pflag.FlagSet, p *bool) {
flags.BoolVarP(p, "trace", "t", false, "enable tracing")
}
func AddVerboseFlag(flags *pflag.FlagSet, p *bool) {
flags.BoolVarP(p, "verbose", "v", false, "print debug logs")
}
func AddExperimentalFlag(flags *pflag.FlagSet, p *bool) {
flags.BoolVar(p, "experimental", false, "accepts the usage of experimental features")
}
func AddGitHubFlags(flags *pflag.FlagSet, p *GitHubClientOptions) {
var (
defURL = getEnv("GH_API_URL", "GITHUB_API_URL")
defToken = getEnv("GH_TOKEN", "GITHUB_TOKEN")
defAppID = getInt64Env("GH_APP_ID", "GITHUB_APP_ID")
defAppPrivKey = getEnv("GH_APP_PRIVATE_KEY", "GITHUB_APP_PRIVATE_KEY")
defInstallationID = getInt64Env("GH_INSTALLATION_ID", "GITHUB_INSTALLATION_ID")
)
if defURL == "" {
defURL = githubclient.DefaultBaseURL
}
flags.StringVar(&p.BaseURL, "github-api-url", defURL, "base url GitHub API")
flags.StringVar(&p.Token, "github-token", defToken, "token for GitHub")
flags.Int64Var(&p.AppID, "github-app-id", defAppID, "id for GitHub App")
flags.StringVar(&p.AppPrivateKey, "github-app-private-key", defAppPrivKey, "base64-encoded private key for GitHub App")
flags.Int64Var(&p.InstallationID, "github-installation-id", defInstallationID, "installation ID for GitHub App")
}
================================================
FILE: cmd/rsr/internal/cmdutil/io.go
================================================
package cmdutil
import (
"context"
"io"
"os"
"github.com/rs/zerolog"
)
// GetInputReader returns an io.ReadCloser. If filename
// is not empty, the file is opened and returned. Otherwise,
// returns a reader from standard input.
func GetInputReader(ctx context.Context, filename string) (r io.ReadCloser, err error) {
var (
logger = zerolog.Ctx(ctx)
file = os.Stdin
)
if filename == "" || filename == "-" {
logger.Debug().Msg("using standard input as INPUT")
} else {
logger.Debug().Msgf("using %s as INPUT", filename)
file, err = os.Open(filename)
if err != nil {
return nil, err
}
}
return file, nil
}
// GetOutputWriter returns an io.WriteCloser. If filename
// is not empty, the file is opened and returned. Otherwise,
// returns a writer to standard output.
func GetOutputWriter(ctx context.Context, filename string) (w io.WriteCloser, err error) {
var (
logger = zerolog.Ctx(ctx)
file = os.Stdout
)
if filename == "" || filename == "-" {
logger.Debug().Msg("using standard output as OUTPUT")
} else {
logger.Debug().Msgf("using %s as OUTPUT", filename)
file, err = os.OpenFile(filename, os.O_WRONLY+os.O_CREATE+os.O_TRUNC, 0o666)
if err != nil {
return nil, err
}
}
return file, nil
}
================================================
FILE: cmd/rsr/internal/cmdutil/logger.go
================================================
package cmdutil
import (
"os"
"github.com/rs/zerolog"
)
// NewLogger returns a new logger that outputs to
// the standard error output. If verbose is true,
// the log level will be `debug`, otherwise will be info.
func NewLogger(verbose bool) zerolog.Logger {
var (
lvl = zerolog.InfoLevel
cw = zerolog.ConsoleWriter{Out: os.Stderr}
)
if verbose {
lvl = zerolog.DebugLevel
}
return zerolog.New(cw).Level(lvl).With().Timestamp().Logger()
}
================================================
FILE: cmd/rsr/internal/exec/exec.go
================================================
package exec
import (
"context"
"encoding/json"
"errors"
"io"
"os"
"sync"
"time"
"github.com/reposaur/reposaur/cmd/rsr/internal/cmdutil"
"github.com/reposaur/reposaur/pkg/output"
"github.com/reposaur/reposaur/pkg/sdk"
"github.com/reposaur/reposaur/provider/github"
githubclient "github.com/reposaur/reposaur/provider/github/client"
"github.com/rs/zerolog"
"github.com/spf13/cobra"
)
type execParams struct {
policyPaths []string
outputFilename string
inputFilename string
enableTracing bool
github cmdutil.GitHubClientOptions
}
func NewCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "exec [-p POLICY_PATH...] [-n NAMESPACE] [-o OUTPUT] INPUT",
Short: "Executes policies against INPUT data",
Long: "Executes policies against INPUT data",
}
var (
params = &execParams{}
flags = cmd.Flags()
)
cmdutil.AddOutputFlag(flags, ¶ms.outputFilename)
cmdutil.AddPolicyPathsFlag(flags, ¶ms.policyPaths)
cmdutil.AddTraceFlag(flags, ¶ms.enableTracing)
cmdutil.AddGitHubFlags(flags, ¶ms.github)
cmd.Run = func(cmd *cobra.Command, args []string) {
var (
ctx = cmd.Context()
logger = zerolog.Ctx(ctx)
)
if len(args) > 1 {
logger.Fatal().Strs("args", args).Msg("too many arguments for INPUT")
}
if len(args) == 1 {
params.inputFilename = args[0]
}
inReader, err := cmdutil.GetInputReader(ctx, params.inputFilename)
if err != nil {
logger.Fatal().Err(err).Msg("failed to get input reader")
}
defer func() {
if err := inReader.Close(); err != nil {
logger.Fatal().Err(err).Msg("failed to close input reader")
}
}()
outWriter, err := cmdutil.GetOutputWriter(ctx, params.outputFilename)
if err != nil {
logger.Fatal().Err(err).Msg("failed to get output writer")
}
defer func() {
if err := outWriter.Close(); err != nil {
logger.Fatal().Err(err).Msg("failed to close output reader")
}
}()
githubProvider, err := newGitHubProvider(ctx, ¶ms.github)
if err != nil {
logger.Fatal().Err(err).Msg("failed to create GitHub provider")
}
opts := []sdk.Option{
sdk.WithLogger(*logger),
sdk.WithProvider(githubProvider),
sdk.WithTracingEnabled(params.enableTracing),
}
rsr, err := sdk.New(ctx, params.policyPaths, opts...)
if err != nil {
logger.Fatal().Err(err).Msg("could not instantiate SDK")
}
runExec(ctx, rsr, inReader, outWriter)
}
return cmd
}
// runExec will execute the policies against the data available
// in inReader. The resulting reports will be outputted to outWriter.
func runExec(ctx context.Context, rsr *sdk.Reposaur, inReader io.ReadCloser, outWriter io.WriteCloser) {
startTime := time.Now()
var (
inputsCh = make(chan interface{})
inputsWg = sync.WaitGroup{}
reportsCh = make(chan output.Report)
reportsWg = sync.WaitGroup{}
logger = zerolog.Ctx(ctx)
)
// Process inputs
go func() {
for input := range inputsCh {
inputsWg.Done()
reportsWg.Add(1)
go func(input interface{}) {
logger.Debug().Msg("processing input")
report, err := rsr.Check(ctx, input)
if err != nil {
logger.Fatal().Err(err).Send()
}
logger.Debug().Msg("done processing input")
reportsCh <- report
}(input)
}
}()
// Output reports
go func() {
enc := json.NewEncoder(outWriter)
enc.SetIndent("", " ")
for report := range reportsCh {
sarif, err := output.NewSarifReport(report)
if err != nil {
logger.Fatal().Err(err).Send()
}
if err := enc.Encode(sarif); err != nil {
logger.Fatal().Err(err).Send()
}
reportsWg.Done()
}
}()
// Start processing inputs
dec := json.NewDecoder(inReader)
for {
var input interface{}
if err := dec.Decode(&input); errors.Is(err, io.EOF) {
break
} else if err != nil {
logger.Fatal().Err(err).Msg("failed to decode input")
}
switch inputT := input.(type) {
case map[string]interface{}:
logger.Debug().Msg("received 1 input")
inputsWg.Add(1)
inputsCh <- inputT
case []interface{}:
logger.Debug().Msgf("received %d inputs", len(inputT))
for _, input := range inputT {
inputsWg.Add(1)
inputsCh <- input
}
}
}
inputsWg.Wait()
close(inputsCh)
logger.Debug().Msg("closed inputs channel")
reportsWg.Wait()
close(reportsCh)
logger.Debug().Msg("closed reports channel")
logger.Info().Dur("timeElapsed", time.Since(startTime)).Msg("done")
// TODO: should exit with 1 if there are failed results
os.Exit(0)
}
func newGitHubProvider(ctx context.Context, opts *cmdutil.GitHubClientOptions) (*github.GitHub, error) {
var client *githubclient.Client
if opts.AppID != 0 && opts.InstallationID != 0 && opts.AppPrivateKey != "" {
appClient, err := githubclient.NewAppClient(ctx, opts.BaseURL, opts.AppID, opts.InstallationID, []byte(opts.AppPrivateKey))
if err != nil {
return nil, err
}
client = appClient
} else if opts.Token != "" {
client = githubclient.NewTokenClient(ctx, opts.Token)
}
return github.NewProvider(client), nil
}
================================================
FILE: cmd/rsr/internal/root/root.go
================================================
package root
import (
"github.com/reposaur/reposaur/cmd/rsr/internal/bundle"
"github.com/reposaur/reposaur/cmd/rsr/internal/cmdutil"
"github.com/reposaur/reposaur/cmd/rsr/internal/exec"
"github.com/reposaur/reposaur/cmd/rsr/internal/test"
"github.com/reposaur/reposaur/internal/build"
"github.com/spf13/cobra"
)
type rootParams struct {
verbose bool
}
func NewCmd() *cobra.Command {
cmd := &cobra.Command{
Version: build.Version,
Use: "rsr",
Short: "Reposaur - security & compliance for GitHub metadata",
}
params := &rootParams{}
cmdutil.AddVerboseFlag(cmd.PersistentFlags(), ¶ms.verbose)
cmd.PersistentPreRun = func(cmd *cobra.Command, args []string) {
logger := cmdutil.NewLogger(params.verbose)
cmd.SetContext(
logger.WithContext(cmd.Context()),
)
}
cmd.AddCommand(
exec.NewCmd(),
test.NewCmd(),
bundle.NewCmd(),
)
return cmd
}
================================================
FILE: cmd/rsr/internal/test/test.go
================================================
package test
import (
"context"
"os"
"time"
"github.com/reposaur/reposaur/cmd/rsr/internal/cmdutil"
"github.com/reposaur/reposaur/pkg/sdk"
"github.com/rs/zerolog"
"github.com/spf13/cobra"
)
type testParams struct {
policyPaths []string
outputFilename string
enableTracing bool
}
func NewCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "test POLICY_PATH...",
Short: "Runs the tests available in POLICY_PATH",
Long: "Runs the tests available in POLICY_PATH",
}
var (
params = &testParams{policyPaths: []string{"."}}
flags = cmd.Flags()
)
cmdutil.AddOutputFlag(flags, ¶ms.outputFilename)
cmdutil.AddTraceFlag(flags, ¶ms.enableTracing)
cmd.Run = func(cmd *cobra.Command, args []string) {
var (
ctx = cmd.Context()
logger = zerolog.Ctx(ctx)
)
opts := []sdk.Option{
sdk.WithLogger(*logger),
sdk.WithTracingEnabled(params.enableTracing),
}
if len(args) > 0 {
params.policyPaths = args
}
rsr, err := sdk.New(ctx, params.policyPaths, opts...)
if err != nil {
logger.Fatal().Err(err).Msg("could not instantiate SDK")
}
runTest(ctx, rsr)
}
return cmd
}
// runTest executes policy tests, outputting the results
// to the provided outWriter.
//
// If any test fails, the function will exit with code 1.
// Otherwise, exits with code 0.
func runTest(ctx context.Context, rsr *sdk.Reposaur) {
var (
startTime = time.Now()
logger = zerolog.Ctx(ctx)
)
results, err := rsr.Test(ctx)
if err != nil {
logger.Fatal().Err(err).Msg("failed to execute tests")
}
var failedTests, totalTests int
for _, r := range results {
totalTests++
if r.Fail {
failedTests++
logger.Error().Msg(r.String())
} else {
logger.Info().Msg(r.String())
}
}
testLogger := logger.With().
Int("passed", totalTests-failedTests).
Int("failed", failedTests).
Int("total", totalTests).
Dur("timeElapsed", time.Since(startTime)).
Logger()
if failedTests > 0 {
testLogger.Error().Msg("done")
os.Exit(1)
}
testLogger.Info().Msg("done")
os.Exit(0)
}
================================================
FILE: cmd/rsr/rsr.go
================================================
package main
import (
"fmt"
"os"
"github.com/reposaur/reposaur/cmd/rsr/internal/root"
)
func main() {
if err := root.NewCmd().Execute(); err != nil {
if _, err := fmt.Fprintln(os.Stderr, err); err != nil {
panic(err)
}
os.Exit(1)
}
}
================================================
FILE: go.mod
================================================
module github.com/reposaur/reposaur
go 1.18
require (
github.com/bradleyfalzon/ghinstallation/v2 v2.1.0
github.com/hashicorp/go-retryablehttp v0.7.2
github.com/open-policy-agent/opa v0.48.0
github.com/owenrumney/go-sarif/v2 v2.1.2
github.com/rs/zerolog v1.28.0
github.com/spf13/cobra v1.6.1
github.com/spf13/pflag v1.0.5
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
)
require (
github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/agnivade/levenshtein v1.1.1 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/golang-jwt/jwt/v4 v4.4.1 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-github/v45 v45.2.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
github.com/tchap/go-patricia/v2 v2.3.1 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/yashtewari/glob-intersection v0.1.0 // indirect
golang.org/x/crypto v0.4.0 // indirect
golang.org/x/net v0.5.0 // indirect
golang.org/x/sys v0.4.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
================================================
FILE: go.sum
================================================
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/bradleyfalzon/ghinstallation/v2 v2.1.0 h1:5+NghM1Zred9Z078QEZtm28G/kfDfZN/92gkDlLwGVA=
github.com/bradleyfalzon/ghinstallation/v2 v2.1.0/go.mod h1:Xg3xPRN5Mcq6GDqeUVhFbjEWMb4JHCyWEeeBGEYQoTU=
github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HVHpXvjfy0Dy7g6fuA=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg=
github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/foxcpp/go-mockdns v0.0.0-20210729171921-fb145fc6f897 h1:E52jfcE64UG42SwLmrW0QByONfGynWuzBvm86BoB9z8=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ=
github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github/v45 v45.2.0 h1:5oRLszbrkvxDDqBCNj2hjDZMKmvexaZ1xw/FCD+K3FI=
github.com/google/go-github/v45 v45.2.0/go.mod h1:FObaZJEDSTa/WGCzZ2Z3eoCDXWJKMenWWTrd8jrta28=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0=
github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
github.com/open-policy-agent/opa v0.48.0 h1:s2K823yohAUu/HB4MOPWDhBh88JMKQv7uTr6S89fbM0=
github.com/open-policy-agent/opa v0.48.0/go.mod h1:CsQcksP+qGBxO9oEBj1NnZqKcjgjmTJbRNTzjZB/DXQ=
github.com/owenrumney/go-sarif v1.1.1/go.mod h1:dNDiPlF04ESR/6fHlPyq7gHKmrM0sHUvAGjsoh8ZH0U=
github.com/owenrumney/go-sarif/v2 v2.1.2 h1:PMDK7tXShJ9zsB7bfvlpADH5NEw1dfA9xwU8Xtdj73U=
github.com/owenrumney/go-sarif/v2 v2.1.2/go.mod h1:MSqMMx9WqlBSY7pXoOZWgEsVB4FDNfhcaXDA1j6Sr+w=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ=
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY=
github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes=
github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k=
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/yashtewari/glob-intersection v0.1.0 h1:6gJvMYQlTDOL3dMsPF6J0+26vwX9MB8/1q3uAdhmTrg=
github.com/yashtewari/glob-intersection v0.1.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE=
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
================================================
FILE: install.sh
================================================
#!/bin/sh
set -e
RELEASES_URL="https://github.com/reposaur/reposaur/releases"
FILE_BASENAME="reposaur"
test -z "$VERSION" && VERSION="$(curl -sfL -o /dev/null -w %{url_effective} "$RELEASES_URL/latest" |
rev |
cut -f1 -d'/' |
rev)"
test -z "$VERSION" && {
echo "Unable to get Reposaur version." >&2
exit 1
}
test -z "$TEMP_DIR" && TEMP_DIR="$(mktemp -d)"
test -z "$INSTALLATION_DIR" && INSTALLATION_DIR="${HOME}/.reposaur"
mkdir -p "${INSTALLATION_DIR}/bin"
export TAR_FILE="$TEMP_DIR/${FILE_BASENAME}_$(uname -s)_$(uname -m).tar.gz"
echo "Downloading Reposaur ${VERSION}..."
curl -sfLo "$TAR_FILE" \
"$RELEASES_URL/download/${VERSION}/${FILE_BASENAME}_${VERSION#v}_$(uname -s)_$(uname -m).tar.gz"
echo ""
echo "Installing Reposaur to ${INSTALLATION_DIR}..."
tar -xf "${TAR_FILE}" -C "${INSTALLATION_DIR}"
mv "${INSTALLATION_DIR}/rsr" "${INSTALLATION_DIR}/bin"
# This binary will be deprecated soon
mv "${INSTALLATION_DIR}/reposaur" "${INSTALLATION_DIR}/bin"
echo ""
echo "Done, try running:"
echo "\t${INSTALLATION_DIR}/bin/rsr --help"
echo ""
echo "It's recommended to add the bin directory to your PATH:"
echo "\tPATH=\"\$PATH:${INSTALLATION_DIR}/bin\""
================================================
FILE: internal/build/build.go
================================================
package build
import (
"runtime/debug"
)
// Version is dynamically set by the toolchain.
var Version = "DEV"
func init() {
if Version == "DEV" {
if info, ok := debug.ReadBuildInfo(); ok && info.Main.Version != "(devel)" {
Version = info.Main.Version
}
}
}
================================================
FILE: internal/policy/engine.go
================================================
package policy
import (
"context"
"fmt"
"os"
"strings"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/bundle"
"github.com/open-policy-agent/opa/loader"
"github.com/open-policy-agent/opa/rego"
"github.com/open-policy-agent/opa/topdown"
"github.com/reposaur/reposaur/pkg/output"
)
type Option func(*Engine)
type Engine struct {
modules map[string]*ast.Module
compiler *ast.Compiler
enableTracing bool
}
func Load(_ context.Context, policyPaths []string, opts ...Option) (*Engine, error) {
policies, err := loader.NewFileLoader().
WithProcessAnnotation(true).
Filtered(policyPaths, isRegoFile)
if err != nil {
return nil, &ErrPolicyLoad{err}
}
if len(policies.Modules) == 0 {
return nil, &ErrNoPolicies{policyPaths}
}
modules := policies.ParsedModules()
compiler := ast.NewCompiler().WithEnablePrintStatements(true)
compiler.Compile(modules)
if compiler.Failed() {
return nil, fmt.Errorf("compiler: %w", compiler.Errors)
}
engine := &Engine{
modules: modules,
compiler: compiler,
}
for _, opt := range opts {
opt(engine)
}
return engine, nil
}
// WithTracingEnabled enables or disables policy
// execution tracing.
func WithTracingEnabled(enabled bool) Option {
return func(e *Engine) {
e.enableTracing = enabled
}
}
// Namespaces returns all the namespaces in the engine.
func (e *Engine) Namespaces() []string {
var namespaces []string
for _, module := range e.Modules() {
namespace := strings.Replace(module.Package.Path.String(), "data.", "", 1)
for _, ns := range namespaces {
if ns == namespace {
continue
}
}
namespaces = append(namespaces, namespace)
}
return namespaces
}
// Compiler returns the compiler from the loaded policies.
func (e *Engine) Compiler() *ast.Compiler {
return e.compiler
}
// Modules returns the modules from the loaded policies.
func (e *Engine) Modules() map[string]*ast.Module {
return e.modules
}
func (e *Engine) Check(ctx context.Context, namespace string, input interface{}) (output.Report, error) {
report, err := e.check(ctx, namespace, input)
if err != nil {
return output.Report{}, fmt.Errorf("check: %w", err)
}
return report, nil
}
func (e *Engine) check(ctx context.Context, namespace string, input interface{}) (output.Report, error) {
report := output.Report{
Rules: map[string]*output.Rule{},
Results: map[string]*output.Result{},
}
for _, mod := range e.Modules() {
currNamespace := strings.TrimPrefix(mod.Package.Path.String(), "data.")
if currNamespace != namespace {
continue
}
for _, r := range mod.Rules {
var annotations *ast.Annotations
for _, a := range mod.Annotations {
if a.Scope == "rule" && a.GetTargetPath().String() == r.Ref().String() {
annotations = a
}
}
rule, err := output.NewRule(namespace, r, annotations)
if err != nil {
continue
}
report.AddRule(rule)
}
}
for _, rule := range report.Rules {
var result *output.Result
result, err := e.querySkip(ctx, rule, input)
if err != nil {
return output.Report{}, fmt.Errorf("query skip rule: %s: %w", rule.UID(), err)
}
if !result.Skipped {
result, err = e.queryRule(ctx, rule, input)
if err != nil {
return output.Report{}, fmt.Errorf("query rule: %s: %w", rule.UID(), err)
}
}
report.AddResult(result)
}
return report, nil
}
func (e *Engine) queryRule(ctx context.Context, rule *output.Rule, input interface{}) (*output.Result, error) {
query := fmt.Sprintf("data.%s.%s_%s", rule.Namespace, rule.Kind, rule.ID)
regoInstance := e.buildRegoInstance(query, input)
resultSet, err := regoInstance.Eval(ctx)
if err != nil {
return nil, fmt.Errorf("query eval: %w", err)
}
result := output.Result{
Rule: rule,
Query: query,
Passed: len(resultSet) == 0,
}
return &result, nil
}
func (e *Engine) querySkip(ctx context.Context, rule *output.Rule, input interface{}) (*output.Result, error) {
query := fmt.Sprintf("data.%s.skip[_][_] == %q", rule.Namespace, rule.ID)
regoInstance := e.buildRegoInstance(query, input)
resultSet, err := regoInstance.Eval(ctx)
if err != nil {
return nil, fmt.Errorf("skip query eval: %w", err)
}
result := output.Result{
Rule: rule,
Query: query,
Skipped: len(resultSet) > 0,
}
return &result, nil
}
func (e *Engine) buildRegoInstance(query string, input interface{}) *rego.Rego {
return rego.New(
rego.Query(query),
rego.Input(input),
rego.Compiler(e.compiler),
rego.Trace(e.enableTracing),
rego.StrictBuiltinErrors(true),
rego.PrintHook(topdown.NewPrintHook(os.Stderr)),
)
}
func isRegoFile(_ string, info os.FileInfo, _ int) bool {
return !info.IsDir() && !strings.HasSuffix(info.Name(), bundle.RegoExt)
}
================================================
FILE: internal/policy/errors.go
================================================
package policy
import "fmt"
type ErrPolicyLoad struct {
loaderError error
}
func (e *ErrPolicyLoad) Error() string {
return fmt.Sprintf("load: %v", e.loaderError)
}
type ErrNoPolicies struct {
policyPaths []string
}
func (e *ErrNoPolicies) Error() string {
return fmt.Sprintf("no policy .rego files found in %v", e.policyPaths)
}
================================================
FILE: pkg/output/report.go
================================================
package output
import (
"fmt"
"strings"
"github.com/open-policy-agent/opa/ast"
)
type Severity string
const (
ErrorSeverity = "error"
WarningSeverity = "warning"
NoteSeverity = "note"
)
var SeverityRuleMap = map[string][]string{
ErrorSeverity: {"error", "fail", "violation"},
WarningSeverity: {"warn"},
NoteSeverity: {"note", "info"},
}
var SecuritySeverityMap = map[string]string{
ErrorSeverity: "7",
WarningSeverity: "4",
NoteSeverity: "1",
}
type Report struct {
Rules map[string]*Rule `json:"rules"`
Results map[string]*Result `json:"results"`
RuleCount int `json:"ruleCount"`
Properties ReportProperties `json:"properties"`
}
func (r *Report) AddRule(rule *Rule) {
r.RuleCount++
r.Rules[rule.UID()] = rule
}
func (r *Report) AddResult(result *Result) {
r.Results[result.Rule.UID()] = result
}
type ReportProperties map[string]interface{}
type Result struct {
Rule *Rule `json:"rule"`
Query string `json:"query"`
Skipped bool `json:"skipped"`
Passed bool `json:"passed"`
}
type Rule struct {
ID string `json:"id"`
Title string `json:"title"`
Kind string `json:"kind"`
Severity string `json:"severity"`
SecuritySeverity string `json:"security-severity"`
Description string `json:"description"`
Namespace string `json:"namespace"`
Tags []string `json:"tags"`
}
func NewRule(namespace string, rule *ast.Rule, as *ast.Annotations) (*Rule, error) {
headSplit := strings.SplitN(rule.Head.Name.String(), "_", 2)
if len(headSplit) != 2 {
return nil, fmt.Errorf("new rule: parse id: invalid rule name: %s", rule.Head.Name.String())
}
var (
kind = headSplit[0]
id = headSplit[1]
severity = ""
)
for sev, kinds := range SeverityRuleMap {
for _, k := range kinds {
if k == kind {
severity = sev
break
}
}
if severity != "" {
break
}
}
if severity == "" {
return nil, fmt.Errorf("new rule: could not find severity for %s", kind)
}
r := Rule{
ID: id,
Title: id,
Kind: kind,
Severity: severity,
SecuritySeverity: SecuritySeverityMap[severity],
Namespace: namespace,
}
if as != nil {
if as.Title != "" {
r.Title = as.Title
} else {
r.Title = r.ID
}
if as.Description != "" {
r.Description = as.Description
} else {
r.Description = r.Title
}
if tags, ok := as.Custom["tags"]; ok {
for _, t := range tags.([]interface{}) {
r.Tags = append(r.Tags, t.(string))
}
}
if secSev, ok := as.Custom["security-severity"]; ok {
r.SecuritySeverity = fmt.Sprintf("%v", secSev)
}
}
return &r, nil
}
func (r Rule) CausesFailure() bool {
return r.Severity == ErrorSeverity
}
func (r Rule) UID() string {
return fmt.Sprintf("%s/%s/%s", r.Namespace, r.Kind, r.ID)
}
================================================
FILE: pkg/output/sarif.go
================================================
package output
import (
"strings"
"github.com/owenrumney/go-sarif/v2/sarif"
)
func NewSarifReport(report Report) (*sarif.Report, error) {
sr, err := sarif.New(sarif.Version210)
if err != nil {
return nil, err
}
run := sarif.NewRunWithInformationURI("Reposaur", "https://github.com/reposaur/reposaur")
run.Properties = sarif.Properties{}
for k, v := range report.Properties {
run.Properties[k] = v
}
for _, rule := range report.Rules {
props := sarif.Properties{}
if len(rule.Tags) > 0 {
props["tags"] = rule.Tags
}
if rule.SecuritySeverity != "" {
props["security-severity"] = rule.SecuritySeverity
}
run.AddRule(rule.UID()).
WithName(rule.Title).
WithDescription(rule.Title).
WithFullDescription(
sarif.NewMultiformatMessageString(rule.Description).
WithMarkdown(rule.Description),
).
WithMarkdownHelp(rule.Description).
WithProperties(props)
}
for _, result := range report.Results {
if !result.Passed && !result.Skipped {
run.AddResult(sarif.NewRuleResult(result.Rule.UID()).
WithLevel(strings.ToLower(result.Rule.Severity)).
WithMessage(sarif.NewTextMessage(result.Rule.Title)).
WithLocations([]*sarif.Location{
sarif.NewLocation().WithPhysicalLocation(
sarif.NewPhysicalLocation().
WithArtifactLocation(
sarif.NewSimpleArtifactLocation("."),
),
),
}),
)
}
}
sr.AddRun(run)
return sr, nil
}
================================================
FILE: pkg/sdk/sdk.go
================================================
package sdk
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"os"
"strings"
"github.com/open-policy-agent/opa/compile"
"github.com/open-policy-agent/opa/rego"
"github.com/open-policy-agent/opa/tester"
"github.com/open-policy-agent/opa/topdown"
"github.com/reposaur/reposaur/internal/policy"
"github.com/reposaur/reposaur/pkg/output"
"github.com/reposaur/reposaur/provider"
"github.com/reposaur/reposaur/provider/github"
"github.com/rs/zerolog"
)
var DefaultProviders = []provider.Provider{
github.NewProvider(nil),
}
// Option represents a Reposaur option that can change a
// particular behavior.
type Option func(*Reposaur)
// Reposaur represents an instance of the auditing engine. It can be
// started with several options that control configuration, logging and
// the client to GitHub.
type Reposaur struct {
logger zerolog.Logger
engine *policy.Engine
providers []provider.Provider
enableTracing bool
}
// New returns a new Reposaur instance, loading and
// compiling any policies provided and registering
// the built-in functions.
//
// If an HTTP client isn't passed as an option, a default
// client is created. A default (unauthenticated) client is created
// using `util.GitHubTransport`.
//
// The util functions available in the `util` package can be used to
// create authenticated HTTP clients.
//
// The default HTTP client will use the default host `api.github.com`. Can
// be customized using the `GITHUB_HOST` or `GH_HOST` environment variables.
func New(ctx context.Context, policyPaths []string, opts ...Option) (*Reposaur, error) {
sdk := &Reposaur{
logger: zerolog.New(os.Stderr),
}
for _, opt := range opts {
opt(sdk)
}
if len(sdk.providers) == 0 {
sdk.providers = DefaultProviders
}
for _, p := range sdk.providers {
for _, b := range p.Builtins() {
rego.RegisterBuiltinDyn(b.Func(), b.Impl)
}
}
var err error
sdk.engine, err = policy.Load(ctx, policyPaths, policy.WithTracingEnabled(sdk.enableTracing))
if err != nil {
return nil, err
}
return sdk, nil
}
// WithProvider adds a provider to Reposaur.
func WithProvider(provider provider.Provider) Option {
return func(sdk *Reposaur) {
sdk.providers = append(sdk.providers, provider)
}
}
// WithLogger sets the logger used by Reposaur.
func WithLogger(logger zerolog.Logger) Option {
return func(sdk *Reposaur) {
sdk.logger = logger
}
}
// WithTracingEnabled enables or disables policy
// execution tracing.
func WithTracingEnabled(enabled bool) Option {
return func(sdk *Reposaur) {
sdk.enableTracing = enabled
}
}
// Logger returns Reposaur logger.
func (sdk Reposaur) Logger() zerolog.Logger {
return sdk.logger
}
// Engine returns Reposaur policy engine.
func (sdk Reposaur) Engine() *policy.Engine {
return sdk.engine
}
// Check executes the policies loaded against data. Data is checked against every
// provider to derive a namespace and additional report properties.
func (sdk Reposaur) Check(ctx context.Context, data interface{}) (output.Report, error) {
var (
dataProvider provider.Provider
namespace provider.Namespace
err error
)
for _, p := range sdk.providers {
namespace, err = provider.DeriveNamespace(p, data)
if err != nil {
if errors.Is(err, provider.ErrNonDerivable) {
continue
}
return output.Report{}, err
}
dataProvider = p
}
if dataProvider == nil {
return output.Report{}, errors.New("could not derive a valid namespace from data")
}
report, err := sdk.engine.Check(ctx, string(namespace), data)
if err != nil {
return output.Report{}, err
}
report.Properties, err = provider.DeriveProperties(dataProvider, namespace, data)
if err != nil && !errors.Is(err, provider.ErrNonDerivable) {
return output.Report{}, err
}
return report, nil
}
func (sdk Reposaur) Test(ctx context.Context) ([]*tester.Result, error) {
runner := tester.NewRunner().
EnableTracing(sdk.enableTracing).
CapturePrintOutput(true).
SetCompiler(sdk.engine.Compiler()).
SetModules(sdk.engine.Modules())
ch, err := runner.RunTests(ctx, nil)
if err != nil {
return nil, fmt.Errorf("running tests: %w", err)
}
var rawResults []*tester.Result
for result := range ch {
if result.Error != nil {
return nil, fmt.Errorf("run test: %w", result.Error)
}
rawResults = append(rawResults, result)
buf := new(bytes.Buffer)
topdown.PrettyTrace(buf, result.Trace)
var traces []string
for _, line := range strings.Split(buf.String(), "\n") {
if len(line) > 0 {
traces = append(traces, line)
}
}
for _, t := range traces {
if _, err := fmt.Fprintln(os.Stderr, t); err != nil {
return nil, err
}
}
}
return rawResults, nil
}
// Bundle builds a new OCI-compatible policy bundle.
func (sdk Reposaur) Bundle(ctx context.Context, paths []string, out io.Writer) error {
c := compile.New().
WithOutput(out).
WithTarget("rego").
WithPaths(paths...)
if err := c.Build(ctx); err != nil {
return err
}
return nil
}
================================================
FILE: provider/github/client/client.go
================================================
package client
import (
"context"
"net/http"
"net/url"
"github.com/bradleyfalzon/ghinstallation/v2"
"github.com/hashicorp/go-retryablehttp"
"golang.org/x/oauth2"
)
const (
DefaultBaseURL = "https://api.github.com"
)
type Client struct {
BaseURL *url.URL
client *retryablehttp.Client
appTransport *ghinstallation.Transport
token string
}
func NewClient(httpClient *http.Client) *Client {
baseURL, _ := url.Parse(DefaultBaseURL)
client := newRetryableClient(httpClient)
return &Client{
BaseURL: baseURL,
client: client,
}
}
func NewTokenClient(ctx context.Context, token string) *Client {
tokenSrc := oauth2.StaticTokenSource(&oauth2.Token{
AccessToken: token,
})
oauthClient := oauth2.NewClient(ctx, tokenSrc)
client := NewClient(oauthClient)
client.token = token
return client
}
func NewAppClient(_ context.Context, baseURL string, appID, installationID int64, privateKey []byte) (*Client, error) {
appTransport, err := ghinstallation.New(http.DefaultTransport, appID, installationID, privateKey)
if err != nil {
return nil, err
}
appTransport.BaseURL = baseURL
httpClient := &http.Client{
Transport: appTransport,
}
client := NewClient(httpClient)
client.appTransport = appTransport
return client, nil
}
func (c Client) Client() *http.Client {
return c.client.HTTPClient
}
func (c Client) Token(ctx context.Context) (string, error) {
if c.appTransport != nil {
return c.appTransport.Token(ctx)
}
return c.token, nil
}
func (c Client) NewRequest(method, path string, rawBody any) (*retryablehttp.Request, error) {
u, err := c.BaseURL.Parse(path)
if err != nil {
return nil, err
}
req, err := retryablehttp.NewRequest(method, u.String(), rawBody)
if err != nil {
return nil, err
}
if rawBody != nil {
req.Header.Set("Content-Type", "application/json")
}
req.Header.Set("User-Agent", "reposaur")
return req, nil
}
func (c Client) Do(req *retryablehttp.Request) (*http.Response, error) {
return c.client.Do(req)
}
func newRetryableClient(httpClient *http.Client) *retryablehttp.Client {
client := retryablehttp.NewClient()
if httpClient != nil {
client.HTTPClient = httpClient
}
return client
}
================================================
FILE: provider/github/github.go
================================================
package github
import (
"github.com/reposaur/reposaur/provider"
"github.com/reposaur/reposaur/provider/github/client"
"github.com/reposaur/reposaur/provider/github/internal/builtin"
)
const (
IssueNamespace provider.Namespace = "github.issue"
OrganizationNamespace provider.Namespace = "github.organization"
PullRequestNamespace provider.Namespace = "github.pull_request"
RepositoryNamespace provider.Namespace = "github.repository"
UserNamespace provider.Namespace = "github.user"
)
type GitHub struct {
client *client.Client
dataDeriver *DataDeriver
builtins []provider.Builtin
}
func NewProvider(c *client.Client) *GitHub {
if c == nil {
c = client.NewClient(nil)
}
return &GitHub{
client: c,
builtins: []provider.Builtin{
&builtin.GraphQL{Client: c},
&builtin.Request{Client: c},
},
dataDeriver: &DataDeriver{
namespaceToKeys: map[provider.Namespace][]string{
IssueNamespace: {"reactions", "closed_by"},
OrganizationNamespace: {"login", "members_url"},
PullRequestNamespace: {"base", "head"},
RepositoryNamespace: {"owner", "full_name"},
UserNamespace: {"login", "hireable"},
},
},
}
}
func (gh GitHub) DeriveNamespace(data map[string]any) (provider.Namespace, error) {
return gh.dataDeriver.DeriveNamespace(data)
}
func (gh GitHub) DeriveProperties(namespace provider.Namespace, data map[string]any) (map[string]any, error) {
return gh.dataDeriver.DeriveProperties(namespace, data)
}
func (gh GitHub) Builtins() []provider.Builtin {
return gh.builtins
}
type DataDeriver struct {
namespaceToKeys map[provider.Namespace][]string
}
func (d DataDeriver) DeriveNamespace(data map[string]any) (provider.Namespace, error) {
for namespace, keys := range d.namespaceToKeys {
var matches int
for _, key := range keys {
for dataKey := range data {
if key == dataKey {
matches++
}
}
if matches == len(keys) {
return namespace, nil
}
}
}
return "", provider.ErrNonDerivable
}
func (d DataDeriver) DeriveProperties(namespace provider.Namespace, data map[string]any) (map[string]any, error) {
switch namespace {
case IssueNamespace, PullRequestNamespace:
props := map[string]any{}
if id, ok := data["id"]; ok {
props["id"] = id
}
if nr, ok := data["number"]; ok {
props["number"] = nr
}
return props, nil
case OrganizationNamespace, UserNamespace:
props := map[string]any{}
if login, ok := data["login"]; ok {
props["login"] = login
}
if name, ok := data["name"]; ok {
props["name"] = name
}
return props, nil
case RepositoryNamespace:
props := map[string]any{}
if owner, ok := data["owner"].(map[string]any); ok {
if login, ok := owner["login"]; ok {
props["owner"] = login
}
}
if name, ok := data["name"]; ok {
props["repo"] = name
}
if defaultBranch, ok := data["default_branch"]; ok {
props["default_branch"] = defaultBranch
}
return props, nil
}
return nil, provider.ErrNonDerivable
}
================================================
FILE: provider/github/github_test.go
================================================
package github_test
import (
"testing"
"github.com/reposaur/reposaur/provider"
"github.com/reposaur/reposaur/provider/github"
)
func TestDeriveNamespace(t *testing.T) {
gh := github.NewProvider(nil)
testData := map[provider.Namespace]map[string]any{
github.IssueNamespace: {
"reactions": ":+1:",
"closed_by": "crqra",
},
github.OrganizationNamespace: {
"login": "reposaur",
"members_url": "https://reposaur.com",
},
github.PullRequestNamespace: {
"base": "main",
"head": "feat",
},
github.RepositoryNamespace: {
"owner": "reposaur",
"full_name": "reposaur/reposaur",
},
github.UserNamespace: {
"login": "crqra",
"hireable": true,
},
}
for expected, data := range testData {
namespace, err := gh.DeriveNamespace(data)
if err != nil {
t.Fatalf("testing %s: %s", expected, err)
}
if namespace != expected {
t.Fatalf("expected namespace to be '%s' got '%s'", expected, namespace)
}
}
}
================================================
FILE: provider/github/internal/builtin/graphql.go
================================================
package builtin
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"github.com/hashicorp/go-retryablehttp"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/rego"
"github.com/open-policy-agent/opa/types"
"github.com/reposaur/reposaur/provider/github/client"
)
type GraphQL struct {
Client *client.Client
}
func (gql GraphQL) Func() *rego.Function {
return ®o.Function{
Name: "github.graphql",
Decl: types.NewFunction(
types.Args(
types.S,
types.NewObject(nil, types.NewDynamicProperty(types.S, types.A)),
),
types.A,
),
Memoize: true,
}
}
func (gql GraphQL) Impl(_ rego.BuiltinContext, terms []*ast.Term) (*ast.Term, error) {
req, err := gql.argsToRequest(terms)
if err != nil {
return nil, err
}
resp, err := gql.Client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var finalResp response
dec := json.NewDecoder(resp.Body)
if err := dec.Decode(&finalResp.Body); err != nil {
return nil, err
}
finalResp.StatusCode = resp.StatusCode
if finalResp.StatusCode == http.StatusForbidden {
b := finalResp.Body.(map[string]interface{})
return nil, fmt.Errorf("forbidden: %s", b["message"])
}
val, err := ast.InterfaceToValue(finalResp)
if err != nil {
return nil, err
}
return ast.NewTerm(val), nil
}
func (gql GraphQL) argsToRequest(terms []*ast.Term) (*retryablehttp.Request, error) {
// FIXME: Function receives 2 arguments but terms includes one additional at last index
if len(terms) != 3 {
return nil, fmt.Errorf("wrong number of arguments, expected 2 got %d", len(terms)-1)
}
var (
query string
vars map[string]any
)
if err := ast.As(terms[0].Value, &query); err != nil {
return nil, err
}
if err := ast.As(terms[1].Value, &vars); err != nil {
return nil, err
}
body := map[string]any{
"query": query,
"variables": vars,
}
buf := &bytes.Buffer{}
enc := json.NewEncoder(buf)
enc.SetEscapeHTML(false)
if err := enc.Encode(body); err != nil {
return nil, err
}
return gql.Client.NewRequest(http.MethodPost, "/graphql", buf)
}
================================================
FILE: provider/github/internal/builtin/request.go
================================================
package builtin
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"regexp"
"strconv"
"strings"
"github.com/hashicorp/go-retryablehttp"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/rego"
"github.com/open-policy-agent/opa/types"
"github.com/reposaur/reposaur/provider/github/client"
)
type Request struct {
Client *client.Client
}
func (r Request) Func() *rego.Function {
return ®o.Function{
Name: "github.request",
Decl: types.NewFunction(
types.Args(
types.S,
types.NewObject(nil, types.NewDynamicProperty(types.S, types.A)),
),
types.A,
),
Memoize: true,
}
}
func (r Request) Impl(_ rego.BuiltinContext, terms []*ast.Term) (*ast.Term, error) {
req, err := r.argsToRequest(terms)
if err != nil {
return nil, err
}
resp, err := r.Client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var finalResp response
dec := json.NewDecoder(resp.Body)
if err := dec.Decode(&finalResp.Body); err != nil {
return nil, err
}
finalResp.StatusCode = resp.StatusCode
if finalResp.StatusCode == http.StatusForbidden {
b := finalResp.Body.(map[string]interface{})
return nil, fmt.Errorf("forbidden: %s", b["message"])
}
val, err := ast.InterfaceToValue(finalResp)
if err != nil {
return nil, err
}
return ast.NewTerm(val), nil
}
func (r Request) argsToRequest(terms []*ast.Term) (*retryablehttp.Request, error) {
// FIXME: Function receives 2 arguments but terms includes one additional at last index
if len(terms) != 3 {
return nil, fmt.Errorf("wrong number of arguments, expected 2 got %d", len(terms)-1)
}
var (
path string
data map[string]any
)
if err := ast.As(terms[0].Value, &path); err != nil {
return nil, err
}
if err := ast.As(terms[1].Value, &data); err != nil {
return nil, err
}
method, path, err := r.parsePath(path)
if err != nil {
return nil, err
}
if method != http.MethodGet {
return nil, fmt.Errorf("only GET requests are supported, got '%s'", method)
}
pathParams := r.parsePathParams(path)
for _, p := range pathParams {
v, err := r.valueToString(data[p])
if err != nil {
return nil, err
}
path = strings.Replace(path, "{"+p+"}", v, 1)
delete(data, p)
}
qs := url.Values{}
for k, v := range data {
v, err := r.valueToString(v)
if err != nil {
return nil, err
}
qs.Add(k, v)
delete(data, k)
}
u, err := url.Parse(path)
if err != nil {
return nil, err
}
u.RawQuery = qs.Encode()
return r.Client.NewRequest(method, u.String(), nil)
}
func (r Request) parsePath(p string) (string, string, error) {
pathParts := strings.Split(p, " ")
if len(pathParts) != 2 {
return "", "", fmt.Errorf("wrong number of parts in path, expected 2 got %d", len(pathParts))
}
var (
method = strings.ToUpper(pathParts[0])
path = pathParts[1]
)
return method, path, nil
}
func (r Request) parsePathParams(path string) []string {
regex := regexp.MustCompile(`{[a-z]+}`)
matches := regex.FindAllString(path, -1)
var params []string
for _, v := range matches {
p := strings.Replace(v, "{", "", 1)
p = strings.Replace(p, "}", "", 1)
params = append(params, p)
}
return params
}
func (r Request) valueToString(v interface{}) (string, error) {
switch tv := v.(type) {
case string:
return tv, nil
case json.Number:
return tv.String(), nil
case int64:
return strconv.Itoa(int(tv)), nil
}
return "", fmt.Errorf("parse error: can't parse '%v' to string", v)
}
================================================
FILE: provider/github/internal/builtin/response.go
================================================
package builtin
type response struct {
StatusCode int `json:"status"`
Body interface{} `json:"body"`
}
================================================
FILE: provider/provider.go
================================================
package provider
import (
"encoding/json"
"errors"
"reflect"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/rego"
)
var ErrNonDerivable = errors.New("data is non derivable")
type Namespace string
// DataDeriver is the interface that provides functions to derive a policy
// namespace and report properties from input data for a specific provider.
type DataDeriver interface {
DeriveNamespace(map[string]any) (Namespace, error)
DeriveProperties(Namespace, map[string]any) (map[string]any, error)
}
// Provider is the interface that provides the functions required to work with
// a specific provider, namely a function to register built-in functions in
// the policy engine and functions to derive required information from input data.
// See DataDeriver.
type Provider interface {
DataDeriver
Builtins() []Builtin
}
// Builtin is represents a built-in function in the policy engine. It specifies
// the function signature and the function implementation.
type Builtin interface {
Func() *rego.Function
Impl(rego.BuiltinContext, []*ast.Term) (*ast.Term, error)
}
func DeriveNamespace(deriver DataDeriver, data any) (Namespace, error) {
m, err := dataToMap(data)
if err != nil {
return "", err
}
return deriver.DeriveNamespace(m)
}
func DeriveProperties(deriver DataDeriver, namespace Namespace, data any) (map[string]any, error) {
m, err := dataToMap(data)
if err != nil {
return nil, err
}
return deriver.DeriveProperties(namespace, m)
}
func dataToMap(data any) (map[string]any, error) {
val := reflect.ValueOf(data)
// We can never derive anything from a slice, only from maps or structures
if val.Kind() == reflect.Slice {
return nil, ErrNonDerivable
}
// If data is already a map we just convert it to map[string]any
if val.Kind() == reflect.Map {
m := make(map[string]any, val.Len())
for _, k := range val.MapKeys() {
if k.Kind() == reflect.String {
m[k.String()] = val.MapIndex(k).Interface()
}
}
return m, nil
}
if val.Kind() != reflect.Struct {
return nil, ErrNonDerivable
}
// Here we have a structure, we rely on json package to convert it into
// a map for us.
rawData, err := json.Marshal(data)
if err != nil {
return nil, err
}
var m map[string]any
if err := json.Unmarshal(rawData, &m); err != nil {
return nil, err
}
return m, nil
}
================================================
FILE: provider/provider_test.go
================================================
package provider
import (
"errors"
"testing"
)
func TestMapDataToMap(t *testing.T) {
dataMap := map[string]any{
"foo": "bar",
"bar": 10,
}
m, err := dataToMap(dataMap)
if err != nil {
t.Error(err)
}
if foo, ok := m["foo"]; !ok || foo != "bar" {
t.Fail()
}
if bar, ok := m["bar"]; !ok || bar != 10 {
t.Fail()
}
}
func TestStructDataToMap(t *testing.T) {
dataStruct := struct {
Foo string `json:"foo"`
Bar int `json:"bar"`
}{
Foo: "bar",
Bar: 10,
}
m, err := dataToMap(dataStruct)
if err != nil {
t.Error(err)
}
if foo, ok := m["foo"]; !ok || foo != "bar" {
t.Fail()
}
// JSON numbers are stored as float64 when converting to interface{}
// See https://pkg.go.dev/encoding/json#Unmarshal
if bar, ok := m["bar"]; !ok || bar != 10.0 {
t.Fail()
}
}
func TestAnyDataToMap(t *testing.T) {
_, err := dataToMap(10)
if !errors.Is(err, ErrNonDerivable) {
t.Errorf("expected error '%s' got '%s'", ErrNonDerivable, err)
}
_, err = dataToMap("foo")
if !errors.Is(err, ErrNonDerivable) {
t.Errorf("expected error '%s' got '%s'", ErrNonDerivable, err)
}
_, err = dataToMap([]string{"foo", "bar"})
if !errors.Is(err, ErrNonDerivable) {
t.Errorf("expected error '%s' got '%s'", ErrNonDerivable, err)
}
}
================================================
FILE: scripts/completions.sh
================================================
#!/bin/sh
set -e
rm -rf completions
mkdir completions
for sh in bash zsh fish; do
go run cmd/rsr/rsr.go completion "$sh" > "completions/rsr.$sh"
done
gitextract_j1gkgj0k/
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.yml
│ │ ├── config.yml
│ │ └── feature_request.yml
│ ├── codeowners
│ ├── dependabot.yml
│ └── workflows/
│ └── test.yml
├── .gitignore
├── .goreleaser.yml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── Taskfile.yaml
├── action.yml
├── cmd/
│ └── rsr/
│ ├── internal/
│ │ ├── bundle/
│ │ │ └── bundle.go
│ │ ├── cmdutil/
│ │ │ ├── env.go
│ │ │ ├── flag.go
│ │ │ ├── io.go
│ │ │ └── logger.go
│ │ ├── exec/
│ │ │ └── exec.go
│ │ ├── root/
│ │ │ └── root.go
│ │ └── test/
│ │ └── test.go
│ └── rsr.go
├── go.mod
├── go.sum
├── install.sh
├── internal/
│ ├── build/
│ │ └── build.go
│ └── policy/
│ ├── engine.go
│ └── errors.go
├── pkg/
│ ├── output/
│ │ ├── report.go
│ │ └── sarif.go
│ └── sdk/
│ └── sdk.go
├── provider/
│ ├── github/
│ │ ├── client/
│ │ │ └── client.go
│ │ ├── github.go
│ │ ├── github_test.go
│ │ └── internal/
│ │ └── builtin/
│ │ ├── graphql.go
│ │ ├── request.go
│ │ └── response.go
│ ├── provider.go
│ └── provider_test.go
└── scripts/
└── completions.sh
SYMBOL INDEX (113 symbols across 23 files)
FILE: cmd/rsr/internal/bundle/bundle.go
type bundleParams (line 12) | type bundleParams struct
function NewCmd (line 17) | func NewCmd() *cobra.Command {
FILE: cmd/rsr/internal/cmdutil/env.go
function getEnv (line 11) | func getEnv(keys ...string) string {
function getInt64Env (line 23) | func getInt64Env(keys ...string) int64 {
FILE: cmd/rsr/internal/cmdutil/flag.go
type GitHubClientOptions (line 8) | type GitHubClientOptions struct
function AddPolicyPathsFlag (line 25) | func AddPolicyPathsFlag(flags *pflag.FlagSet, p *[]string) {
function AddOutputFlag (line 29) | func AddOutputFlag(flags *pflag.FlagSet, p *string) {
function AddTraceFlag (line 33) | func AddTraceFlag(flags *pflag.FlagSet, p *bool) {
function AddVerboseFlag (line 37) | func AddVerboseFlag(flags *pflag.FlagSet, p *bool) {
function AddExperimentalFlag (line 41) | func AddExperimentalFlag(flags *pflag.FlagSet, p *bool) {
function AddGitHubFlags (line 45) | func AddGitHubFlags(flags *pflag.FlagSet, p *GitHubClientOptions) {
FILE: cmd/rsr/internal/cmdutil/io.go
function GetInputReader (line 14) | func GetInputReader(ctx context.Context, filename string) (r io.ReadClos...
function GetOutputWriter (line 37) | func GetOutputWriter(ctx context.Context, filename string) (w io.WriteCl...
FILE: cmd/rsr/internal/cmdutil/logger.go
function NewLogger (line 12) | func NewLogger(verbose bool) zerolog.Logger {
FILE: cmd/rsr/internal/exec/exec.go
type execParams (line 21) | type execParams struct
function NewCmd (line 29) | func NewCmd() *cobra.Command {
function runExec (line 104) | func runExec(ctx context.Context, rsr *sdk.Reposaur, inReader io.ReadClo...
function newGitHubProvider (line 200) | func newGitHubProvider(ctx context.Context, opts *cmdutil.GitHubClientOp...
FILE: cmd/rsr/internal/root/root.go
type rootParams (line 12) | type rootParams struct
function NewCmd (line 16) | func NewCmd() *cobra.Command {
FILE: cmd/rsr/internal/test/test.go
type testParams (line 14) | type testParams struct
function NewCmd (line 20) | func NewCmd() *cobra.Command {
function runTest (line 66) | func runTest(ctx context.Context, rsr *sdk.Reposaur) {
FILE: cmd/rsr/rsr.go
function main (line 10) | func main() {
FILE: internal/build/build.go
function init (line 10) | func init() {
FILE: internal/policy/engine.go
type Option (line 17) | type Option
type Engine (line 19) | type Engine struct
method Namespaces (line 67) | func (e *Engine) Namespaces() []string {
method Compiler (line 84) | func (e *Engine) Compiler() *ast.Compiler {
method Modules (line 89) | func (e *Engine) Modules() map[string]*ast.Module {
method Check (line 93) | func (e *Engine) Check(ctx context.Context, namespace string, input in...
method check (line 102) | func (e *Engine) check(ctx context.Context, namespace string, input in...
method queryRule (line 152) | func (e *Engine) queryRule(ctx context.Context, rule *output.Rule, inp...
method querySkip (line 170) | func (e *Engine) querySkip(ctx context.Context, rule *output.Rule, inp...
method buildRegoInstance (line 188) | func (e *Engine) buildRegoInstance(query string, input interface{}) *r...
function Load (line 25) | func Load(_ context.Context, policyPaths []string, opts ...Option) (*Eng...
function WithTracingEnabled (line 60) | func WithTracingEnabled(enabled bool) Option {
function isRegoFile (line 199) | func isRegoFile(_ string, info os.FileInfo, _ int) bool {
FILE: internal/policy/errors.go
type ErrPolicyLoad (line 5) | type ErrPolicyLoad struct
method Error (line 9) | func (e *ErrPolicyLoad) Error() string {
type ErrNoPolicies (line 13) | type ErrNoPolicies struct
method Error (line 17) | func (e *ErrNoPolicies) Error() string {
FILE: pkg/output/report.go
type Severity (line 10) | type Severity
constant ErrorSeverity (line 13) | ErrorSeverity = "error"
constant WarningSeverity (line 14) | WarningSeverity = "warning"
constant NoteSeverity (line 15) | NoteSeverity = "note"
type Report (line 30) | type Report struct
method AddRule (line 37) | func (r *Report) AddRule(rule *Rule) {
method AddResult (line 42) | func (r *Report) AddResult(result *Result) {
type ReportProperties (line 46) | type ReportProperties
type Result (line 48) | type Result struct
type Rule (line 55) | type Rule struct
method CausesFailure (line 132) | func (r Rule) CausesFailure() bool {
method UID (line 136) | func (r Rule) UID() string {
function NewRule (line 66) | func NewRule(namespace string, rule *ast.Rule, as *ast.Annotations) (*Ru...
FILE: pkg/output/sarif.go
function NewSarifReport (line 9) | func NewSarifReport(report Report) (*sarif.Report, error) {
FILE: pkg/sdk/sdk.go
type Option (line 30) | type Option
type Reposaur (line 35) | type Reposaur struct
method Logger (line 106) | func (sdk Reposaur) Logger() zerolog.Logger {
method Engine (line 111) | func (sdk Reposaur) Engine() *policy.Engine {
method Check (line 117) | func (sdk Reposaur) Check(ctx context.Context, data interface{}) (outp...
method Test (line 154) | func (sdk Reposaur) Test(ctx context.Context) ([]*tester.Result, error) {
method Bundle (line 194) | func (sdk Reposaur) Bundle(ctx context.Context, paths []string, out io...
function New (line 55) | func New(ctx context.Context, policyPaths []string, opts ...Option) (*Re...
function WithProvider (line 84) | func WithProvider(provider provider.Provider) Option {
function WithLogger (line 91) | func WithLogger(logger zerolog.Logger) Option {
function WithTracingEnabled (line 99) | func WithTracingEnabled(enabled bool) Option {
FILE: provider/github/client/client.go
constant DefaultBaseURL (line 14) | DefaultBaseURL = "https://api.github.com"
type Client (line 17) | type Client struct
method Client (line 66) | func (c Client) Client() *http.Client {
method Token (line 70) | func (c Client) Token(ctx context.Context) (string, error) {
method NewRequest (line 78) | func (c Client) NewRequest(method, path string, rawBody any) (*retryab...
method Do (line 98) | func (c Client) Do(req *retryablehttp.Request) (*http.Response, error) {
function NewClient (line 25) | func NewClient(httpClient *http.Client) *Client {
function NewTokenClient (line 35) | func NewTokenClient(ctx context.Context, token string) *Client {
function NewAppClient (line 48) | func NewAppClient(_ context.Context, baseURL string, appID, installation...
function newRetryableClient (line 102) | func newRetryableClient(httpClient *http.Client) *retryablehttp.Client {
FILE: provider/github/github.go
constant IssueNamespace (line 10) | IssueNamespace provider.Namespace = "github.issue"
constant OrganizationNamespace (line 11) | OrganizationNamespace provider.Namespace = "github.organization"
constant PullRequestNamespace (line 12) | PullRequestNamespace provider.Namespace = "github.pull_request"
constant RepositoryNamespace (line 13) | RepositoryNamespace provider.Namespace = "github.repository"
constant UserNamespace (line 14) | UserNamespace provider.Namespace = "github.user"
type GitHub (line 17) | type GitHub struct
method DeriveNamespace (line 46) | func (gh GitHub) DeriveNamespace(data map[string]any) (provider.Namesp...
method DeriveProperties (line 50) | func (gh GitHub) DeriveProperties(namespace provider.Namespace, data m...
method Builtins (line 54) | func (gh GitHub) Builtins() []provider.Builtin {
function NewProvider (line 23) | func NewProvider(c *client.Client) *GitHub {
type DataDeriver (line 58) | type DataDeriver struct
method DeriveNamespace (line 62) | func (d DataDeriver) DeriveNamespace(data map[string]any) (provider.Na...
method DeriveProperties (line 82) | func (d DataDeriver) DeriveProperties(namespace provider.Namespace, da...
FILE: provider/github/github_test.go
function TestDeriveNamespace (line 10) | func TestDeriveNamespace(t *testing.T) {
FILE: provider/github/internal/builtin/graphql.go
type GraphQL (line 16) | type GraphQL struct
method Func (line 20) | func (gql GraphQL) Func() *rego.Function {
method Impl (line 34) | func (gql GraphQL) Impl(_ rego.BuiltinContext, terms []*ast.Term) (*as...
method argsToRequest (line 68) | func (gql GraphQL) argsToRequest(terms []*ast.Term) (*retryablehttp.Re...
FILE: provider/github/internal/builtin/request.go
type Request (line 19) | type Request struct
method Func (line 23) | func (r Request) Func() *rego.Function {
method Impl (line 37) | func (r Request) Impl(_ rego.BuiltinContext, terms []*ast.Term) (*ast....
method argsToRequest (line 71) | func (r Request) argsToRequest(terms []*ast.Term) (*retryablehttp.Requ...
method parsePath (line 133) | func (r Request) parsePath(p string) (string, string, error) {
method parsePathParams (line 148) | func (r Request) parsePathParams(path string) []string {
method valueToString (line 162) | func (r Request) valueToString(v interface{}) (string, error) {
FILE: provider/github/internal/builtin/response.go
type response (line 3) | type response struct
FILE: provider/provider.go
type Namespace (line 14) | type Namespace
type DataDeriver (line 18) | type DataDeriver interface
type Provider (line 27) | type Provider interface
type Builtin (line 35) | type Builtin interface
function DeriveNamespace (line 40) | func DeriveNamespace(deriver DataDeriver, data any) (Namespace, error) {
function DeriveProperties (line 49) | func DeriveProperties(deriver DataDeriver, namespace Namespace, data any...
function dataToMap (line 58) | func dataToMap(data any) (map[string]any, error) {
FILE: provider/provider_test.go
function TestMapDataToMap (line 8) | func TestMapDataToMap(t *testing.T) {
function TestStructDataToMap (line 28) | func TestStructDataToMap(t *testing.T) {
function TestAnyDataToMap (line 53) | func TestAnyDataToMap(t *testing.T) {
Condensed preview — 42 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (129K chars).
[
{
"path": ".github/FUNDING.yml",
"chars": 26,
"preview": "github: [reposaur, crqra]\n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.yml",
"chars": 1446,
"preview": "name: Bug Report\ndescription: File a bug report\n\ntitle: \"[Bug]: \"\nlabels: [\"bug\", \"triage\"]\n\nbody:\n - type: markdown\n "
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 156,
"preview": "blank_issues_enabled: true\ncontact_links:\n - name: Ask a question\n url: https://github.com/orgs/reposaur/discussions"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.yml",
"chars": 1282,
"preview": "name: Feature Request\ndescription: Suggest a new idea or feature to add to Reposaur\n\ntitle: \"[Feature]: \"\nlabels: [\"enha"
},
{
"path": ".github/codeowners",
"chars": 8,
"preview": "* @crqra"
},
{
"path": ".github/dependabot.yml",
"chars": 109,
"preview": "version: 2\nupdates:\n - package-ecosystem: \"gomod\"\n directory: \"/\"\n schedule:\n interval: \"weekly\"\n"
},
{
"path": ".github/workflows/test.yml",
"chars": 1901,
"preview": "name: Test\n\non:\n push:\n branches:\n - main\n pull_request:\n\nenv:\n GO111MODULE: on\n\njobs:\n golangci-lint:\n n"
},
{
"path": ".gitignore",
"chars": 146,
"preview": "# Used for local tests only\n/config.yaml\n/policy/\n/testdata/events/_*.json\ndist/\nbin/\n\n# Generated\n/completions\n\n# Edito"
},
{
"path": ".goreleaser.yml",
"chars": 3209,
"preview": "before:\n hooks:\n - go mod tidy\n - go vet ./...\n - ./scripts/completions.sh\n\nbuilds:\n - id: rsr\n binary: rs"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 5218,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
},
{
"path": "CONTRIBUTING.md",
"chars": 2850,
"preview": "# Contributing\n\nBeforehand, thank you for considering contributing to Reposaur! We welcome and\nappreciate any help we ca"
},
{
"path": "LICENSE",
"chars": 1096,
"preview": "MIT License\n\nCopyright (c) 2022 João Cerqueira and Reposaur contributors\n\nPermission is hereby granted, free of charge, "
},
{
"path": "README.md",
"chars": 5432,
"preview": "<div align=\"center\">\n\n[![logo][logo]][website]\n\n# Reposaur\n\n[![go-report][go-report-badge]][go-report]\n[![tests-workflow"
},
{
"path": "Taskfile.yaml",
"chars": 1046,
"preview": "# https://taskfile.dev\n\nversion: \"3\"\n\ntasks:\n deps:\n run: once\n cmds:\n - go mod tidy\n silent: true\n\n bui"
},
{
"path": "action.yml",
"chars": 520,
"preview": "name: Reposaur\nauthor: Reposaur Authors\ndescription: Audit your GitHub data using custom policies written in Rego\n\nbrand"
},
{
"path": "cmd/rsr/internal/bundle/bundle.go",
"chars": 1544,
"preview": "package bundle\n\nimport (\n\t\"os\"\n\n\t\"github.com/reposaur/reposaur/cmd/rsr/internal/cmdutil\"\n\t\"github.com/reposaur/reposaur/"
},
{
"path": "cmd/rsr/internal/cmdutil/env.go",
"chars": 714,
"preview": "package cmdutil\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n)\n\n// getEnv looks up every key in keys in the environment variables a"
},
{
"path": "cmd/rsr/internal/cmdutil/flag.go",
"chars": 1982,
"preview": "package cmdutil\n\nimport (\n\tgithubclient \"github.com/reposaur/reposaur/provider/github/client\"\n\t\"github.com/spf13/pflag\"\n"
},
{
"path": "cmd/rsr/internal/cmdutil/io.go",
"chars": 1255,
"preview": "package cmdutil\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/rs/zerolog\"\n)\n\n// GetInputReader returns an io.ReadCloser"
},
{
"path": "cmd/rsr/internal/cmdutil/logger.go",
"chars": 458,
"preview": "package cmdutil\n\nimport (\n\t\"os\"\n\n\t\"github.com/rs/zerolog\"\n)\n\n// NewLogger returns a new logger that outputs to\n// the st"
},
{
"path": "cmd/rsr/internal/exec/exec.go",
"chars": 5005,
"preview": "package exec\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io\"\n\t\"os\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/reposaur/reposaur"
},
{
"path": "cmd/rsr/internal/root/root.go",
"chars": 888,
"preview": "package root\n\nimport (\n\t\"github.com/reposaur/reposaur/cmd/rsr/internal/bundle\"\n\t\"github.com/reposaur/reposaur/cmd/rsr/in"
},
{
"path": "cmd/rsr/internal/test/test.go",
"chars": 2056,
"preview": "package test\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/reposaur/reposaur/cmd/rsr/internal/cmdutil\"\n\t\"github.com/r"
},
{
"path": "cmd/rsr/rsr.go",
"chars": 251,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/reposaur/reposaur/cmd/rsr/internal/root\"\n)\n\nfunc main() {\n\tif err := r"
},
{
"path": "go.mod",
"chars": 1642,
"preview": "module github.com/reposaur/reposaur\n\ngo 1.18\n\nrequire (\n\tgithub.com/bradleyfalzon/ghinstallation/v2 v2.1.0\n\tgithub.com/h"
},
{
"path": "go.sum",
"chars": 48142,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1"
},
{
"path": "install.sh",
"chars": 1179,
"preview": "#!/bin/sh\nset -e\n\nRELEASES_URL=\"https://github.com/reposaur/reposaur/releases\"\nFILE_BASENAME=\"reposaur\"\n\ntest -z \"$VERSI"
},
{
"path": "internal/build/build.go",
"chars": 269,
"preview": "package build\n\nimport (\n\t\"runtime/debug\"\n)\n\n// Version is dynamically set by the toolchain.\nvar Version = \"DEV\"\n\nfunc in"
},
{
"path": "internal/policy/engine.go",
"chars": 4746,
"preview": "package policy\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/open-policy-agent/opa/ast\"\n\t\"github.com/open-p"
},
{
"path": "internal/policy/errors.go",
"chars": 339,
"preview": "package policy\n\nimport \"fmt\"\n\ntype ErrPolicyLoad struct {\n\tloaderError error\n}\n\nfunc (e *ErrPolicyLoad) Error() string {"
},
{
"path": "pkg/output/report.go",
"chars": 2898,
"preview": "package output\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/open-policy-agent/opa/ast\"\n)\n\ntype Severity string\n\nconst (\n\tEr"
},
{
"path": "pkg/output/sarif.go",
"chars": 1435,
"preview": "package output\n\nimport (\n\t\"strings\"\n\n\t\"github.com/owenrumney/go-sarif/v2/sarif\"\n)\n\nfunc NewSarifReport(report Report) (*"
},
{
"path": "pkg/sdk/sdk.go",
"chars": 4999,
"preview": "package sdk\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/open-policy-agent/opa/co"
},
{
"path": "provider/github/client/client.go",
"chars": 2203,
"preview": "package client\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/url\"\n\n\t\"github.com/bradleyfalzon/ghinstallation/v2\"\n\t\"github.com/h"
},
{
"path": "provider/github/github.go",
"chars": 3027,
"preview": "package github\n\nimport (\n\t\"github.com/reposaur/reposaur/provider\"\n\t\"github.com/reposaur/reposaur/provider/github/client\""
},
{
"path": "provider/github/github_test.go",
"chars": 975,
"preview": "package github_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/reposaur/reposaur/provider\"\n\t\"github.com/reposaur/reposaur/provid"
},
{
"path": "provider/github/internal/builtin/graphql.go",
"chars": 2091,
"preview": "package builtin\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/hashicorp/go-retryablehttp\"\n\t\"githu"
},
{
"path": "provider/github/internal/builtin/request.go",
"chars": 3489,
"preview": "package builtin\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/h"
},
{
"path": "provider/github/internal/builtin/response.go",
"chars": 120,
"preview": "package builtin\n\ntype response struct {\n\tStatusCode int `json:\"status\"`\n\tBody interface{} `json:\"body\"`\n}\n"
},
{
"path": "provider/provider.go",
"chars": 2361,
"preview": "package provider\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"reflect\"\n\n\t\"github.com/open-policy-agent/opa/ast\"\n\t\"github.com/o"
},
{
"path": "provider/provider_test.go",
"chars": 1263,
"preview": "package provider\n\nimport (\n\t\"errors\"\n\t\"testing\"\n)\n\nfunc TestMapDataToMap(t *testing.T) {\n\tdataMap := map[string]any{\n\t\t\""
},
{
"path": "scripts/completions.sh",
"chars": 150,
"preview": "#!/bin/sh\nset -e\nrm -rf completions\nmkdir completions\nfor sh in bash zsh fish; do\n\tgo run cmd/rsr/rsr.go completion \"$sh"
}
]
About this extraction
This page contains the full source code of the reposaur/reposaur GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 42 files (117.1 KB), approximately 46.4k tokens, and a symbol index with 113 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.