diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..755f4b1 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.go] +indent_style = tab + +[*.yaml] +indent_size = 2 + +[{Makefile,*.mk}] +indent_style = tab + +[*.nix] +indent_size = 2 diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3ce7171 --- /dev/null +++ b/.envrc @@ -0,0 +1,4 @@ +if ! has nix_direnv_version || ! nix_direnv_version 2.3.0; then + source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.3.0/direnvrc" "sha256-Dmd+j63L84wuzgyjITIfSxSD57Tx7v51DMxVZOsiUD8=" +fi +use flake . --impure diff --git a/.github/.editorconfig b/.github/.editorconfig new file mode 100644 index 0000000..0902c6a --- /dev/null +++ b/.github/.editorconfig @@ -0,0 +1,2 @@ +[{*.yml,*.yaml}] +indent_size = 2 diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml new file mode 100644 index 0000000..e63ea97 --- /dev/null +++ b/.github/dependabot.yaml @@ -0,0 +1,17 @@ +version: 2 + +updates: + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "daily" + + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "daily" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 0000000..6edfd4f --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "schedule:earlyMondays", + ":disableDependencyDashboard" + ], + "enabledManagers": [ + "nix" + ], + "nix": { + "enabled": true + }, + "lockFileMaintenance": { + "enabled": true + } +} diff --git a/.github/workflows/analysis-scorecard.yaml b/.github/workflows/analysis-scorecard.yaml new file mode 100644 index 0000000..56f6753 --- /dev/null +++ b/.github/workflows/analysis-scorecard.yaml @@ -0,0 +1,47 @@ +name: OpenSSF Scorecard + +on: + branch_protection_rule: + push: + branches: [main] + schedule: + - cron: '30 0 * * 5' + +permissions: + contents: read + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + permissions: + actions: read + contents: read + id-token: write + security-events: write + + steps: + - name: Checkout repository + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + with: + persist-credentials: false + + - name: Run analysis + uses: ossf/scorecard-action@08b4669551908b1024bb425080c797723083c031 # v2.2.0 + with: + results_file: results.sarif + results_format: sarif + publish_results: true + + - name: Upload results as artifact + uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + with: + name: OpenSSF Scorecard results + path: results.sarif + retention-days: 5 + + - name: Upload results to GitHub Security tab + uses: github/codeql-action/upload-sarif@cdcdbb579706841c47f7063dda365e292e5cad7a # v2.3.4 + with: + sarif_file: results.sarif diff --git a/.github/workflows/artifacts.yaml b/.github/workflows/artifacts.yaml new file mode 100644 index 0000000..d541e42 --- /dev/null +++ b/.github/workflows/artifacts.yaml @@ -0,0 +1,195 @@ +name: Artifacts + +on: + workflow_call: + inputs: + publish: + description: Publish artifacts to the artifact store + default: false + required: false + type: boolean + release: + description: Whether this is a release build + default: false + required: false + type: boolean + outputs: + container-image-name: + description: Container image name + value: ${{ jobs.container-image.outputs.name }} + container-image-digest: + description: Container image digest + value: ${{ jobs.container-image.outputs.digest }} + container-image-tag: + description: Container image tag + value: ${{ jobs.container-image.outputs.tag }} + container-image-ref: + description: Container image ref + value: ${{ jobs.container-image.outputs.ref }} + +permissions: + contents: read + +jobs: + container-image: + name: Container image + runs-on: ubuntu-latest + + permissions: + contents: read + packages: write + id-token: write + security-events: write + + outputs: + name: ${{ steps.image-name.outputs.value }} + digest: ${{ steps.build.outputs.digest }} + tag: ${{ steps.meta.outputs.version }} + ref: ${{ steps.image-ref.outputs.value }} + + steps: + - name: Checkout repository + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + + - name: Set up QEMU + uses: docker/setup-qemu-action@2b82ce82d56a2a04d2637cd93a637ae1b359c0a7 # v2.2.0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@885d1462b80bc1c1c7f0b00334ad271f09369c55 # v2.10.0 + + - name: Set image name + id: image-name + run: echo "value=ghcr.io/${{ github.repository }}" >> "$GITHUB_OUTPUT" + + - name: Gather build metadata + id: meta + uses: docker/metadata-action@818d4b7b91585d195f67373fd9cb0332e31a7175 # v4.6.0 + with: + images: ${{ steps.image-name.outputs.value }} + flavor: | + latest = false + tags: | + type=ref,event=branch + type=ref,event=pr,prefix=pr- + type=semver,pattern={{raw}} + type=raw,value=latest,enable={{is_default_branch}} + + # Multiple exporters are not supported yet + # See https://github.com/moby/buildkit/pull/2760 + - name: Determine build output + uses: haya14busa/action-cond@1d6e8a12b20cdb4f1954feef9aa475b9c390cab5 # v1.1.1 + id: build-output + with: + cond: ${{ inputs.publish }} + if_true: type=image,push=true + if_false: type=oci,dest=image.tar + + - name: Login to GitHub Container Registry + uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # v2.2.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ github.token }} + if: inputs.publish + + - name: Build and push image + id: build + uses: docker/build-push-action@2eb1c1961a95fc15694676618e422e8ba1d63825 # v4.1.1 + with: + context: . + platforms: linux/amd64,linux/arm64,linux/arm/v7 + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + outputs: ${{ steps.build-output.outputs.value }} + # push: ${{ inputs.publish }} + + - name: Set image ref + id: image-ref + run: echo "value=${{ steps.image-name.outputs.value }}@${{ steps.build.outputs.digest }}" >> "$GITHUB_OUTPUT" + + - name: Fetch image + run: skopeo --insecure-policy copy docker://${{ steps.image-name.outputs.value }}:${{ steps.meta.outputs.version }} oci-archive:image.tar + if: inputs.publish + + - name: Upload image as artifact + uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + with: + name: "[${{ github.job }}] OCI tarball" + path: image.tar + + - name: Extract OCI tarball + run: | + mkdir -p image + tar -xf image.tar -C image + + # See https://github.com/anchore/syft/issues/1545 + - name: Extract image from multi-arch image + run: skopeo --override-os linux --override-arch amd64 --insecure-policy copy --additional-tag ${{ steps.image-name.outputs.value }}:${{ steps.meta.outputs.version }} oci:image docker-archive:docker.tar + + - name: Upload image as artifact + uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + with: + name: "[${{ github.job }}] Docker tarball" + path: docker.tar + + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@fbd16365eb88e12433951383f5e99bd901fc618f # 0.12.0 + with: + input: image + format: sarif + output: trivy-results.sarif + + - name: Upload Trivy scan results as artifact + uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + with: + name: "[${{ github.job }}] Trivy scan results" + path: trivy-results.sarif + retention-days: 5 + + - name: Upload Trivy scan results to GitHub Security tab + uses: github/codeql-action/upload-sarif@cdcdbb579706841c47f7063dda365e292e5cad7a # v2.13.4 + with: + sarif_file: trivy-results.sarif + + binary: + name: Binary + runs-on: ubuntu-latest + + permissions: + contents: write + + steps: + - name: Checkout repository + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + + - name: Set up Nix + uses: cachix/install-nix-action@6a9a9e84a173d90b3ffb42c5ddaf9ea033fad011 # v23 + with: + extra_nix_config: | + access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} + + - name: Prepare Nix shell + run: nix develop --impure .#ci + + - name: Determine build command + uses: haya14busa/action-cond@1d6e8a12b20cdb4f1954feef9aa475b9c390cab5 # v1.1.1 + id: build-command + with: + cond: ${{ inputs.release }} + if_true: goreleaser release + if_false: goreleaser release --skip-publish --snapshot + + - name: Build + run: nix develop --impure .#ci -c ${{ steps.build-command.outputs.value }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload artifacts + uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + with: + name: "${{ github.job }}" + path: | + build/dist/*.tar.gz + build/dist/checksums.txt diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..2cb8d5e --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,205 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +jobs: + build: + name: Build + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + + - name: Set up Nix + uses: cachix/install-nix-action@6a9a9e84a173d90b3ffb42c5ddaf9ea033fad011 # v23 + with: + extra_nix_config: | + access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} + + - name: Set up magic Nix cache + uses: DeterminateSystems/magic-nix-cache-action@8a218f9e264e9c3803c9a1ee1c30d8e4ab55be63 # v2 + + - name: Set up Go cache + uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ github.job }}-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ github.job }}-${{ runner.os }}-go- + + - name: Prepare Nix shell + run: nix develop --impure .#ci + + - name: Build + run: nix develop --impure .#ci -c make build + + test: + name: Test + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + + - name: Set up Nix + uses: cachix/install-nix-action@6a9a9e84a173d90b3ffb42c5ddaf9ea033fad011 # v23 + with: + extra_nix_config: | + access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} + + - name: Set up magic Nix cache + uses: DeterminateSystems/magic-nix-cache-action@8a218f9e264e9c3803c9a1ee1c30d8e4ab55be63 # v2 + + - name: Set up Go cache + uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ github.job }}-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ github.job }}-${{ runner.os }}-go- + + - name: Prepare Nix shell + run: nix develop --impure .#ci + + - name: Test + run: nix develop --impure .#ci -c make test + + lint: + name: Lint + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + + - name: Set up Nix + uses: cachix/install-nix-action@6a9a9e84a173d90b3ffb42c5ddaf9ea033fad011 # v23 + with: + extra_nix_config: | + access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} + + - name: Set up magic Nix cache + uses: DeterminateSystems/magic-nix-cache-action@8a218f9e264e9c3803c9a1ee1c30d8e4ab55be63 # v2 + + - name: Set up Go cache + uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ github.job }}-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ github.job }}-${{ runner.os }}-go- + + - name: Prepare Nix shell + run: nix develop --impure .#ci + + - name: Lint + run: nix develop --impure .#ci -c make lint + + license-check: + name: License check + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + + - name: Set up Nix + uses: cachix/install-nix-action@6a9a9e84a173d90b3ffb42c5ddaf9ea033fad011 # v23 + with: + extra_nix_config: | + access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} + + - name: Set up magic Nix cache + uses: DeterminateSystems/magic-nix-cache-action@8a218f9e264e9c3803c9a1ee1c30d8e4ab55be63 # v2 + + - name: Set up Go cache + uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ github.job }}-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ github.job }}-${{ runner.os }}-go- + + - name: Cache license information + uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + with: + path: .licensei.cache + key: licensei-v1-${{ github.ref_name }}-${{ hashFiles('go.sum') }} + restore-keys: | + licensei-v1-${{ github.ref_name }} + licensei-v1-main + licensei-v1 + + - name: Prepare Nix shell + run: nix develop --impure .#ci + + - name: Populate license cache + run: nix develop --impure .#ci -c licensei cache + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Check licenses + run: nix develop --impure .#ci -c make license-check + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + dev: + name: Developer environment + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + + - name: Set up Nix + uses: cachix/install-nix-action@6a9a9e84a173d90b3ffb42c5ddaf9ea033fad011 # v23 + with: + extra_nix_config: | + access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} + + - name: Set up magic Nix cache + uses: DeterminateSystems/magic-nix-cache-action@8a218f9e264e9c3803c9a1ee1c30d8e4ab55be63 # v2 + + - name: Check + run: nix flake check --impure + + - name: Dev shell + run: nix develop --impure + + artifacts: + name: Artifacts + uses: ./.github/workflows/artifacts.yaml + with: + publish: ${{ github.event_name == 'push' }} + permissions: + contents: write + packages: write + id-token: write + security-events: write + + dependency-review: + name: Dependency review + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + + steps: + - name: Checkout repository + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + + - name: Dependency Review + uses: actions/dependency-review-action@f6fff72a3217f580d5afd49a46826795305b63c7 # v3.0.8 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..791eeca --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,23 @@ +name: Release + +on: + push: + tags: + - "v[0-9]+.[0-9]+.[0-9]+" + - "v[0-9]+.[0-9]+.[0-9]+-alpha.[0-9]+" + +permissions: + contents: read + +jobs: + artifacts: + name: Artifacts + uses: ./.github/workflows/artifacts.yaml + with: + publish: true + release: true + permissions: + contents: write + packages: write + id-token: write + security-events: write diff --git a/.gitignore b/.gitignore index 3558c56..5a3cd4b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ -bin/ -build/ +/.devenv/ +/.direnv/ +/.pre-commit-config.yaml +/bin/ +/build/ +/tmp/ diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000..539dc61 --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,27 @@ +run: + timeout: 10m + +linters-settings: + gci: + sections: + - standard + - default + - prefix(github.com/bank-vaults/secret-sync) + goimports: + local-prefixes: github.com/bank-vaults/secret-sync + misspell: + locale: US + nolintlint: + allow-leading-space: false # require machine-readable nolint directives (with no leading space) + allow-unused: false # report any unused nolint directives + require-specific: false # don't require nolint directives to be specific about which linter is being skipped + revive: + confidence: 0 + +linters: + enable: + - gci + - goimports + - misspell + - nolintlint + - revive diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 0000000..aa04569 --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,32 @@ +dist: build/dist + +builds: + - main: . + env: + - CGO_ENABLED=0 + flags: + - -trimpath + ldflags: "-s -w -X main.version={{ .Version }}" + goos: + - linux + - darwin + goarch: + - amd64 + - arm64 + +archives: + - name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}" + format_overrides: + - goos: windows + format: zip + +checksum: + name_template: "checksums.txt" + +changelog: + skip: false + +release: + draft: true + replace_existing_draft: true + prerelease: auto diff --git a/.yamllint.yaml b/.yamllint.yaml index bac19ce..9278ed2 100644 --- a/.yamllint.yaml +++ b/.yamllint.yaml @@ -1,4 +1,4 @@ -ignore-from-file: [.gitignore, .yamlignore] +ignore-from-file: [.gitignore] extends: default diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a1e15db --- /dev/null +++ b/Dockerfile @@ -0,0 +1,36 @@ +FROM --platform=$BUILDPLATFORM tonistiigi/xx:1.2.1@sha256:8879a398dedf0aadaacfbd332b29ff2f84bc39ae6d4e9c0a1109db27ac5ba012 AS xx + +FROM --platform=$BUILDPLATFORM golang:1.21.0-alpine3.18@sha256:445f34008a77b0b98bf1821bf7ef5e37bb63cc42d22ee7c21cc17041070d134f AS builder + +COPY --from=xx / / + +RUN apk add --update --no-cache ca-certificates make git curl clang lld + +ARG TARGETPLATFORM + +RUN xx-apk --update --no-cache add musl-dev gcc + +RUN xx-go --wrap + +WORKDIR /usr/local/src/secret-sync + +ARG GOPROXY + +ENV CGO_ENABLED=0 + +COPY go.* ./ +RUN go mod download + +COPY . . + +RUN go build -o /usr/local/bin/secret-sync . +RUN xx-verify /usr/local/bin/secret-sync + + +FROM alpine:3.18.3@sha256:7144f7bab3d4c2648d7e59409f15ec52a18006a128c733fcff20d3a4a54ba44a + +RUN apk add --update --no-cache ca-certificates tzdata + +COPY --from=builder /usr/local/bin/secret-sync /usr/local/bin/secret-sync + +USER 65534 diff --git a/cmd/sync.go b/cmd/sync.go index 54e8c82..853cd9f 100644 --- a/cmd/sync.go +++ b/cmd/sync.go @@ -18,15 +18,17 @@ import ( "context" "encoding/json" "fmt" - "github.com/bank-vaults/secret-sync/pkg/apis/v1alpha1" - "github.com/bank-vaults/secret-sync/pkg/provider" - "github.com/bank-vaults/secret-sync/pkg/storesync" + "os" + "os/signal" + "github.com/ghodss/yaml" "github.com/krayzpipes/cronticker/cronticker" "github.com/sirupsen/logrus" "github.com/spf13/cobra" - "os" - "os/signal" + + "github.com/bank-vaults/secret-sync/pkg/apis/v1alpha1" + "github.com/bank-vaults/secret-sync/pkg/provider" + "github.com/bank-vaults/secret-sync/pkg/storesync" ) func NewSyncCmd() *cobra.Command { diff --git a/cmd/sync_test.go b/cmd/sync_test.go index d238f47..ab85cd0 100644 --- a/cmd/sync_test.go +++ b/cmd/sync_test.go @@ -16,10 +16,11 @@ package cmd import ( "fmt" - "github.com/stretchr/testify/assert" "os" "path/filepath" "testing" + + "github.com/stretchr/testify/assert" ) func TestSync(t *testing.T) { diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..2fa03d2 --- /dev/null +++ b/flake.lock @@ -0,0 +1,273 @@ +{ + "nodes": { + "devenv": { + "inputs": { + "flake-compat": "flake-compat", + "nix": "nix", + "nixpkgs": "nixpkgs", + "pre-commit-hooks": "pre-commit-hooks" + }, + "locked": { + "lastModified": 1694097209, + "narHash": "sha256-gQmBjjxeSyySjbh0yQVBKApo2KWIFqqbRUvG+Fa+QpM=", + "owner": "cachix", + "repo": "devenv", + "rev": "7a8e6a91510efe89d8dcb8e43233f93e86f6b189", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1693611461, + "narHash": "sha256-aPODl8vAgGQ0ZYFIRisxYG5MOGSkIczvu2Cd8Gb9+1Y=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "7f53fdb7bdc5bb237da7fefef12d099e4fd611ca", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1685518550, + "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "devenv", + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1660459072, + "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "lowdown-src": { + "flake": false, + "locked": { + "lastModified": 1633514407, + "narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=", + "owner": "kristapsdz", + "repo": "lowdown", + "rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8", + "type": "github" + }, + "original": { + "owner": "kristapsdz", + "repo": "lowdown", + "type": "github" + } + }, + "nix": { + "inputs": { + "lowdown-src": "lowdown-src", + "nixpkgs": [ + "devenv", + "nixpkgs" + ], + "nixpkgs-regression": "nixpkgs-regression" + }, + "locked": { + "lastModified": 1676545802, + "narHash": "sha256-EK4rZ+Hd5hsvXnzSzk2ikhStJnD63odF7SzsQ8CuSPU=", + "owner": "domenkozar", + "repo": "nix", + "rev": "7c91803598ffbcfe4a55c44ac6d49b2cf07a527f", + "type": "github" + }, + "original": { + "owner": "domenkozar", + "ref": "relaxed-flakes", + "repo": "nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1678875422, + "narHash": "sha256-T3o6NcQPwXjxJMn2shz86Chch4ljXgZn746c2caGxd8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "126f49a01de5b7e35a43fd43f891ecf6d3a51459", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "dir": "lib", + "lastModified": 1693471703, + "narHash": "sha256-0l03ZBL8P1P6z8MaSDS/MvuU8E75rVxe5eE1N6gxeTo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "3e52e76b70d5508f3cec70b882a29199f4d1ee85", + "type": "github" + }, + "original": { + "dir": "lib", + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-regression": { + "locked": { + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1685801374, + "narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c37ca420157f4abc31e26f436c1145f8951ff373", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1694098687, + "narHash": "sha256-59I+rW3/UyOy5jgjkwoNdImL9TJujZYAZinT5ML3fYU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "1d07743667b6ad1e149a539d3d4ead66d31da901", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "master", + "repo": "nixpkgs", + "type": "github" + } + }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": [ + "devenv", + "flake-compat" + ], + "flake-utils": "flake-utils", + "gitignore": "gitignore", + "nixpkgs": [ + "devenv", + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1688056373, + "narHash": "sha256-2+SDlNRTKsgo3LBRiMUcoEUb6sDViRNQhzJquZ4koOI=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "5843cf069272d92b60c3ed9e55b7a8989c01d4c7", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "root": { + "inputs": { + "devenv": "devenv", + "flake-parts": "flake-parts", + "nixpkgs": "nixpkgs_2" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..1e091eb --- /dev/null +++ b/flake.nix @@ -0,0 +1,129 @@ +{ + description = "Synchronise secrets between services in a configurable manner"; + + inputs = { + # nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + nixpkgs.url = "github:NixOS/nixpkgs/master"; + flake-parts.url = "github:hercules-ci/flake-parts"; + devenv.url = "github:cachix/devenv"; + }; + + outputs = inputs@{ flake-parts, ... }: + flake-parts.lib.mkFlake { inherit inputs; } { + imports = [ + inputs.devenv.flakeModule + ]; + + systems = [ "x86_64-linux" "x86_64-darwin" "aarch64-darwin" ]; + + perSystem = { config, self', inputs', pkgs, system, ... }: rec { + devenv.shells = { + default = { + languages = { + go.enable = true; + go.package = pkgs.go_1_21; + }; + + services = { + vault.enable = true; + }; + + pre-commit.hooks = { + nixpkgs-fmt.enable = true; + yamllint.enable = true; + # hadolint.enable = true; + }; + + packages = with pkgs; [ + gnumake + + # golangci-lint + goreleaser + + yamllint + # hadolint + ] ++ [ + self'.packages.licensei + self'.packages.golangci-lint + ]; + + env = { + VAULT_ADDR = "http://127.0.0.1:8200"; + VAULT_TOKEN = "227e1cce-6bf7-30bb-2d2a-acc854318caf"; + }; + + # https://github.com/cachix/devenv/issues/528#issuecomment-1556108767 + containers = pkgs.lib.mkForce { }; + }; + + ci = devenv.shells.default; + }; + + packages = { + # TODO: create flake in source repo + licensei = pkgs.buildGoModule rec { + pname = "licensei"; + version = "0.8.0"; + + src = pkgs.fetchFromGitHub { + owner = "goph"; + repo = "licensei"; + rev = "v${version}"; + sha256 = "sha256-Pvjmvfk0zkY2uSyLwAtzWNn5hqKImztkf8S6OhX8XoM="; + }; + + vendorSha256 = "sha256-ZIpZ2tPLHwfWiBywN00lPI1R7u7lseENIiybL3+9xG8="; + + subPackages = [ "cmd/licensei" ]; + + ldflags = [ + "-w" + "-s" + "-X main.version=v${version}" + ]; + }; + + golangci-lint = pkgs.buildGo121Module rec { + pname = "golangci-lint"; + version = "1.54.2"; + + src = pkgs.fetchFromGitHub { + owner = "golangci"; + repo = "golangci-lint"; + rev = "v${version}"; + hash = "sha256-7nbgiUrp7S7sXt7uFXX8NHYbIRLZZQcg+18IdwAZBfE="; + }; + + vendorHash = "sha256-IyH5lG2a4zjsg/MUonCUiAgMl4xx8zSflRyzNgk8MR0="; + + subPackages = [ "cmd/golangci-lint" ]; + + nativeBuildInputs = [ pkgs.installShellFiles ]; + + ldflags = [ + "-s" + "-w" + "-X main.version=${version}" + "-X main.commit=v${version}" + "-X main.date=19700101-00:00:00" + ]; + + postInstall = '' + for shell in bash zsh fish; do + HOME=$TMPDIR $out/bin/golangci-lint completion $shell > golangci-lint.$shell + installShellCompletion golangci-lint.$shell + done + ''; + + meta = with pkgs.lib; { + description = "Fast linters Runner for Go"; + homepage = "https://golangci-lint.run/"; + changelog = "https://github.com/golangci/golangci-lint/blob/v${version}/CHANGELOG.md"; + license = licenses.gpl3Plus; + maintainers = with maintainers; [ anpryl manveru mic92 ]; + }; + }; + }; + }; + }; +} diff --git a/go.mod b/go.mod index cee071a..5bb30cf 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/bank-vaults/secret-sync -go 1.20 +go 1.21 require ( github.com/bank-vaults/vault-sdk v0.9.0 diff --git a/go.sum b/go.sum index d062857..be63833 100644 --- a/go.sum +++ b/go.sum @@ -7,6 +7,7 @@ cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2Aawl cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= emperror.dev/errors v0.8.1 h1:UavXZ5cSX/4u9iyvH6aDcuGkVjeexUGJ7Ij7G4VfQT0= emperror.dev/errors v0.8.1/go.mod h1:YcRvLPh626Ubn2xqtoprejnA5nFha+TJ+2vew48kWuE= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -33,11 +34,13 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= +github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 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= @@ -80,6 +83,7 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3veNs= +github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= @@ -117,8 +121,10 @@ github.com/leosayous21/go-azure-msi v0.0.0-20210509193526-19353bedcfc8 h1:C9EWiK github.com/leosayous21/go-azure-msi v0.0.0-20210509193526-19353bedcfc8/go.mod h1:GfJ7YCWVSRJBC6YwUyO1Is2v+HaTrwR3yMfS92tIIWo= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= diff --git a/main.go b/main.go index 2fa49c8..6cdb4c6 100644 --- a/main.go +++ b/main.go @@ -15,8 +15,9 @@ package main import ( - "github.com/bank-vaults/secret-sync/cmd" "github.com/sirupsen/logrus" + + "github.com/bank-vaults/secret-sync/cmd" ) func main() { diff --git a/pkg/apis/v1alpha1/syncjob_types.go b/pkg/apis/v1alpha1/syncjob_types.go index 5bd1480..e339a79 100644 --- a/pkg/apis/v1alpha1/syncjob_types.go +++ b/pkg/apis/v1alpha1/syncjob_types.go @@ -15,10 +15,11 @@ package v1alpha1 import ( - "github.com/robfig/cron" - "github.com/sirupsen/logrus" "os" "path/filepath" + + "github.com/robfig/cron" + "github.com/sirupsen/logrus" ) var ( diff --git a/pkg/provider/file/client.go b/pkg/provider/file/client.go index 636f32b..1220b0f 100644 --- a/pkg/provider/file/client.go +++ b/pkg/provider/file/client.go @@ -17,10 +17,11 @@ package file import ( "context" "fmt" - "github.com/bank-vaults/secret-sync/pkg/apis/v1alpha1" "os" "path/filepath" "strings" + + "github.com/bank-vaults/secret-sync/pkg/apis/v1alpha1" ) type client struct { diff --git a/pkg/provider/file/provider.go b/pkg/provider/file/provider.go index e2d336a..bef7b14 100644 --- a/pkg/provider/file/provider.go +++ b/pkg/provider/file/provider.go @@ -17,6 +17,7 @@ package file import ( "context" "fmt" + "github.com/bank-vaults/secret-sync/pkg/apis/v1alpha1" ) diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index ac67320..f403a38 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -17,8 +17,8 @@ package provider import ( "context" "fmt" - "github.com/bank-vaults/secret-sync/pkg/apis/v1alpha1" + "github.com/bank-vaults/secret-sync/pkg/apis/v1alpha1" // Register providers _ "github.com/bank-vaults/secret-sync/pkg/provider/file" _ "github.com/bank-vaults/secret-sync/pkg/provider/vault" diff --git a/pkg/provider/vault/client.go b/pkg/provider/vault/client.go index 8c4ccf4..b72e7c2 100644 --- a/pkg/provider/vault/client.go +++ b/pkg/provider/vault/client.go @@ -17,10 +17,12 @@ package vault import ( "context" "fmt" - "github.com/bank-vaults/secret-sync/pkg/apis/v1alpha1" + "strings" + "github.com/bank-vaults/vault-sdk/vault" "github.com/spf13/cast" - "strings" + + "github.com/bank-vaults/secret-sync/pkg/apis/v1alpha1" ) type client struct { @@ -123,6 +125,7 @@ func (c *client) SetSecret(_ context.Context, key v1alpha1.SecretKey, value []by // Not used since it has high memory footprint and does not handle search. // It could (potentially) be useful. // DEPRECATED +//nolint func (c *client) recursiveList(ctx context.Context, path string) ([]v1alpha1.SecretKey, error) { // List API request response, err := c.apiClient.RawClient().Logical().List(fmt.Sprintf("%s/metadata/%s", c.apiKeyPath, path)) diff --git a/pkg/provider/vault/provider.go b/pkg/provider/vault/provider.go index 46019d3..bd8c175 100644 --- a/pkg/provider/vault/provider.go +++ b/pkg/provider/vault/provider.go @@ -17,8 +17,10 @@ package vault import ( "context" "fmt" - "github.com/bank-vaults/secret-sync/pkg/apis/v1alpha1" + "github.com/bank-vaults/vault-sdk/vault" + + "github.com/bank-vaults/secret-sync/pkg/apis/v1alpha1" ) type Provider struct{} diff --git a/pkg/storesync/storesync.go b/pkg/storesync/storesync.go index 7cdcb2f..a2c92b5 100644 --- a/pkg/storesync/storesync.go +++ b/pkg/storesync/storesync.go @@ -17,12 +17,14 @@ package storesync import ( "context" "fmt" - "github.com/bank-vaults/secret-sync/pkg/apis/v1alpha1" - "github.com/sirupsen/logrus" "regexp" "sync" "sync/atomic" "time" + + "github.com/sirupsen/logrus" + + "github.com/bank-vaults/secret-sync/pkg/apis/v1alpha1" ) // syncRequest defines data required to perform a key sync. diff --git a/pkg/storesync/storesync_test.go b/pkg/storesync/storesync_test.go index 4b39a89..9dd0c8d 100644 --- a/pkg/storesync/storesync_test.go +++ b/pkg/storesync/storesync_test.go @@ -16,14 +16,16 @@ package storesync_test import ( "context" - "github.com/bank-vaults/secret-sync/pkg/apis/v1alpha1" - "github.com/bank-vaults/secret-sync/pkg/provider" - "github.com/bank-vaults/secret-sync/pkg/storesync" - "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" "io" "os" "testing" + + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + + "github.com/bank-vaults/secret-sync/pkg/apis/v1alpha1" + "github.com/bank-vaults/secret-sync/pkg/provider" + "github.com/bank-vaults/secret-sync/pkg/storesync" ) func BenchmarkSync(b *testing.B) { @@ -141,7 +143,7 @@ func createVaultStore(t *testing.T, addr, token string) v1alpha1.StoreClient { type fakeClient struct{} -func (c *fakeClient) GetSecret(_ context.Context, key v1alpha1.SecretKey) ([]byte, error) { +func (c *fakeClient) GetSecret(_ context.Context, _ v1alpha1.SecretKey) ([]byte, error) { return []byte(""), nil } @@ -149,6 +151,6 @@ func (c *fakeClient) ListSecretKeys(_ context.Context, _ v1alpha1.SecretKeyQuery return []v1alpha1.SecretKey{{}, {}}, nil } -func (c *fakeClient) SetSecret(_ context.Context, key v1alpha1.SecretKey, value []byte) error { +func (c *fakeClient) SetSecret(_ context.Context, _ v1alpha1.SecretKey, _ []byte) error { return nil }