diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 6346ff1..eba061e 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -4,10 +4,11 @@ This is a single top-level namespace filled with packages. Each directory is potentially a package. Binary builds are done on packages with a main subpackage. -## Install Golang +## Install Golang -### Using asdf-vm -We utilize a `.go-version` file that can be used by [asdf-vm](https://github.com/kennyp/asdf-golang) like so: +### Using asdf or rtx + +We utilize a `.go-version` file that can be used by [asdf-vm](https://github.com/kennyp/asdf-golang) or [rtx](https://github.com/jdxcode/rtx) like so: ```bash cd /path/to/sopstool/repository/ @@ -24,13 +25,6 @@ cd /path/to/sopstool/repository/ goenv install ``` -### Using gimme -[gimme](https://github.com/travis-ci/gimme) uses `eval` in a simple way: - -```bash -eval "$(gimme 1.17)" -``` - ### From the developers You can download and install the Golang [directly from the website](https://go.dev/dl/). @@ -126,10 +120,6 @@ Summary: Given a version number **MAJOR**.**MINOR**.**PATCH**, increment the: ## Patterns -### Godownloader - -We used to use [godownloader](https://github.com/goreleaser/godownloader) to generate the installer scripts. This is deprecated now, but the majority of the scripts used have not changed in a while. Any fixes will need to be by-hand. - ### Common third-party modules in use - cobra diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index c01edcb..7f88b53 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -29,6 +29,9 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 + - name: Set up Syft + uses: anchore/sbom-action/download-syft@v0 + - name: Set up Go uses: actions/setup-go@v4 with: @@ -62,6 +65,6 @@ jobs: env: # this needs push access to the tap GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} - - name: upload other artifacts - shell: bash - run: scripts/deploy + + - name: Push Docker + run: scripts/deploy-docker --push diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 25971ab..852541f 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -26,6 +26,9 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 + - name: Set up Syft + uses: anchore/sbom-action/download-syft@v0 + - name: Set up Go uses: actions/setup-go@v4 with: @@ -47,3 +50,6 @@ jobs: distribution: goreleaser version: latest args: release --clean --snapshot --skip-publish + + - name: Test Docker + run: scripts/deploy-docker diff --git a/.gitignore b/.gitignore index 8b0d0c4..360ec69 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ sopstool c.out *.cover .idea -.vscode \ No newline at end of file +.vscode +bin diff --git a/.goreleaser.yml b/.goreleaser.yml index c86370d..c492de2 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,3 +1,5 @@ +report_sizes: true + # Build customization builds: - env: @@ -6,32 +8,41 @@ builds: goos: - darwin - linux + - windows goarch: - amd64 - arm64 + goarm: + - "" + goamd64: + - "" + +universal_binaries: + - id: sopstool + # Whether to remove the previous single-arch binaries from the artifact list. + # If left as false, your end release might have both several macOS archives: + # amd64, arm64 and all. + replace: true archives: - id: newzips name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}" + format_overrides: + - goos: windows + format: zip checksum: - # You can change the name of the checksums file. - # This is parsed with the Go template engine and the following variables - # are available: - # - ProjectName - # - Tag - # - Version (Git tag without `v` prefix) - # - Env (environment variables) # Default is `{{ .ProjectName }}_{{ .Version }}_checksums.txt`. name_template: "{{ .ProjectName }}_checksums.txt" +sboms: + - artifacts: binary + documents: ["{{ .Binary }}_{{ .Os }}_{{ .Arch }}.sbom"] + nfpms: - id: default # You can change the file name of the package. - # - # Default: `{{ .PackageName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}` file_name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}" - # file_name_template: "{{ .ProjectName }}_{{ .Os }}" vendor: Ibotta homepage: https://github.com/Ibotta/sopstool maintainer: Ibotta @@ -41,6 +52,7 @@ nfpms: formats: - deb - rpm + - apk # Packages your package depends on. dependencies: - sops @@ -81,73 +93,15 @@ blobs: bucket: oss-pkg.ibotta.com # AWS Region to use. region: us-east-1 - # path inside the bucket. - # This is parsed with the Go template engine and the following variables - # are available: - # - ProjectName - # - Tag - # - Version (Git tag without `v` prefix) - # There is also a template function "time" that takes a Go time format - # string to insert a formated timestamp into the release name. - # Default is `{{ .ProjectName }}/{{ .Tag }}` - # folder: + # Default: '{{ .ProjectName }}/{{ .Tag }}' + folder: "{{ .ProjectName }}/{{ .Tag }}" - provider: s3 bucket: oss-pkg.ibotta.com region: us-east-1 folder: "{{ .ProjectName }}" - -dockers: - - id: amd64image - goos: linux - # GOARCH of the built binary that should be used. - goarch: amd64 - # GOARM of the built binary that should be used. - goarm: "" - # Name templates of the built binaries that should be used. - ids: - - sopstool - # Templates of the Docker image names. - image_templates: - - "ibotta/{{ .ProjectName }}:latest" - - "ibotta/{{ .ProjectName }}:{{ .Version }}" - - "ibotta/{{ .ProjectName }}:{{ .Tag }}" - - "ibotta/{{ .ProjectName }}:v{{ .Major }}" - - "ibotta/{{ .ProjectName }}:v{{ .Major }}.{{ .Minor }}" - - "ibotta/{{ .ProjectName }}:latest-amd64" - - "ibotta/{{ .ProjectName }}:{{ .Version }}-amd64" - - "ibotta/{{ .ProjectName }}:{{ .Tag }}-amd64" - - "ibotta/{{ .ProjectName }}:v{{ .Major }}-amd64" - - "ibotta/{{ .ProjectName }}:v{{ .Major }}.{{ .Minor }}-amd64" - - "ghcr.io/ibotta/{{ .ProjectName }}:latest" - - "ghcr.io/ibotta/{{ .ProjectName }}:{{ .Version }}" - - "ghcr.io/ibotta/{{ .ProjectName }}:{{ .Tag }}" - - "ghcr.io/ibotta/{{ .ProjectName }}:v{{ .Major }}" - - "ghcr.io/ibotta/{{ .ProjectName }}:v{{ .Major }}.{{ .Minor }}" - - "ghcr.io/ibotta/{{ .ProjectName }}:latest-amd64" - - "ghcr.io/ibotta/{{ .ProjectName }}:{{ .Version }}-amd64" - - "ghcr.io/ibotta/{{ .ProjectName }}:{{ .Tag }}-amd64" - - "ghcr.io/ibotta/{{ .ProjectName }}:v{{ .Major }}-amd64" - - "ghcr.io/ibotta/{{ .ProjectName }}:v{{ .Major }}.{{ .Minor }}-amd64" - # Skips the docker push. Could be useful if you also do draft releases. - # If set to auto, the release will not be pushed to the docker repository - # in case there is an indicator for prerelease in the tag e.g. v1.0.0-rc1 - # Defaults to false. - skip_push: false - # Path to the Dockerfile (from the project root). - dockerfile: Dockerfile - # Template of the docker build flags. - build_flag_templates: - - "--label=org.label-schema.schema-version=1.0" - - "--label=org.label-schema.version={{.Version}}" - - "--label=org.label-schema.name={{.ProjectName}}" - # If your Dockerfile copies files other than the binary itself, - # you should list them here as well. - # Note that goreleaser will create the same structure inside the temporary - # folder, so if you add `foo/bar.json` here, on your Dockerfile you can - # `COPY foo/bar.json /whatever.json`. - # Also note that the paths here are relative to the folder in which - # goreleaser is being run. - # This field does not support wildcards, you can add an entire folder here - # and use wildcards when you `COPY`/`ADD` in your Dockerfile. extra_files: - - sopsinstall.sh + - glob: ./*install.sh + +publishers: + - name: deploy-sops + cmd: ./scripts/deploy-sops diff --git a/Dockerfile b/Dockerfile index 7377d19..247c0b6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,14 @@ FROM alpine:latest as build +ARG TARGETARCH + RUN apk --update add ca-certificates +# download appropriate sops (script gets latest) COPY sopsinstall.sh /tmp/sopsinstall.sh -RUN sh /tmp/sopsinstall.sh -b /usr/local/bin +RUN sh /tmp/sopsinstall.sh -b /usr/local/bin -a $TARGETARCH + +# grab appropriate sopstool binary from dist +COPY dist/sopstool_linux_$TARGETARCH/sopstool /usr/local/bin/sopstool ########## @@ -13,7 +19,7 @@ COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certifica # get sops COPY --from=build usr/local/bin/sops /usr/local/bin/sops # get sopstool -COPY sopstool /usr/local/bin/sopstool +COPY --from=build usr/local/bin/sopstool /usr/local/bin/sopstool WORKDIR /work diff --git a/README.md b/README.md index 9f3ceb7..b635125 100644 --- a/README.md +++ b/README.md @@ -1,136 +1,158 @@ # sopstool -[![Build Status](https://travis-ci.org/Ibotta/sopstool.svg?branch=master)](https://travis-ci.org/Ibotta/sopstool) [![Maintainability](https://api.codeclimate.com/v1/badges/addf39da73692548e1e3/maintainability)](https://codeclimate.com/github/Ibotta/sopstool/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/addf39da73692548e1e3/test_coverage)](https://codeclimate.com/github/Ibotta/sopstool/test_coverage) +[![Maintainability](https://api.codeclimate.com/v1/badges/addf39da73692548e1e3/maintainability)](https://codeclimate.com/github/Ibotta/sopstool/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/addf39da73692548e1e3/test_coverage)](https://codeclimate.com/github/Ibotta/sopstool/test_coverage) sopstool is a multi-file wrapper around [sops](https://github.com/mozilla/sops). It uses the sops binary to encrypt and decrypt files, and piggybacks off the .sops.yaml configuration file. sopstool provides functionality to manage multiple secret files at once, and even use as an entrypoint to decrypt at startup, for container images. Much of this behavior is inspired by the great [blackbox project](https://github.com/StackExchange/blackbox). +- [sopstool](#sopstool) + - [1.0.0 Release and Breaking Changes](#100-release-and-breaking-changes) + - [Installation](#installation) + - [Package Repositories](#package-repositories) + - [Container Image](#container-image) + - [Packages or binaries from Releases](#packages-or-binaries-from-releases) + - [Shell installer](#shell-installer) + - [Installing sops manually](#installing-sops-manually) + - [Installing the sops binary with our script installer](#installing-the-sops-binary-with-our-script-installer) + - [Download sops from our https mirror](#download-sops-from-our-https-mirror) + - [Installing sopstool manually](#installing-sopstool-manually) + - [Installing the sopstool binary using our script installer](#installing-the-sopstool-binary-using-our-script-installer) + - [Download sopstool from our https mirror](#download-sopstool-from-our-https-mirror) + - [Usage](#usage) + - [Configuration](#configuration) + - [How-To](#how-to) + - [Walkthrough](#walkthrough) + - [Contributing](#contributing) + - [docs](#docs) + ## 1.0.0 Release and Breaking Changes -1.0.0 release of `sopstool` introduces M1 / darwin-arm64 support. We also want to match build artifacts produced by GoReleaser to what `sops` produces. Therefore, this version introduces a breaking change where we no longer produce artifacts like `sopstool_linux.(deb|rpm|tar.gz)` and `sopstool_darwin.tar.gz`. Instead, you'll see artifacts like `sopstool_darwin_(arm64|amd64)_(deb|rpm|tar.gz)` and `sopstool_linux_(arm64|amd64)_(deb|rpm|tar.gz)` in future releases. + +1.0.0 release of `sopstool` introduces M1 / darwin-arm64 support. We also want to match build artifacts produced by GoReleaser to what `sops` produces. Therefore, this version introduces a breaking change where we no longer produce artifacts like `sopstool_linux.(deb|rpm|tar.gz)` and `sopstool_darwin.tar.gz`. Instead, you'll see artifacts like `sopstool_darwin_(arm64|amd64)_(deb|rpm|tar.gz)` and `sopstool_linux_(arm64|amd64)_(deb|rpm|tar.gz)` in future releases. ## Installation -The most direct install uses a shell script hosted in this repository. This script will install the latest sops (if the command does not exist) and sopstool to `./bin` by default. +### Package Repositories -```sh -curl https://raw.githubusercontent.com/Ibotta/sopstool/master/install.sh | bash -``` +sopstool is available in the following repositories -- Override the sops version with the environment variable `SOPS_VERSION` -- Override the sopstool version with the environment variable `SOPSTOOL_VERSION` -- Override the binary install location with the first shell argument - - remember, you may need `sudo` or root access if you are installing to `/usr/*` +- homebrew via the `Ibotta/public` tap: `brew install Ibotta/public/sopstool` +- asdf (and rtx) via the `sopstool` plugin: `asdf plugin add sopstool` -Example with overrides: +### Container Image -```sh -curl https://raw.githubusercontent.com/Ibotta/sopstool/master/install.sh | SOPS_VERSION=3.0.0 SOPSTOOL_VERSION=0.3.0 bash -s /usr/local/bin -``` +Images are tagged with the same version numbering as the releases, and `latest` always gets the latest release. Note that your image will need root CA certificates (typically installed with curl, or a `ca-certificates` package). -### Docker +To use sopstool from container (avoiding doing binary installs): -**Note**: We currently only build a docker image for [Linux - amd64](.goreleaser.yml#L100). +```sh +docker run --rm -v $(pwd):/work -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_REGION -e AWS_SECURITY_TOKEN -e AWS_SESSION_TOKEN ghcr.io/ibotta/sopstool:latest $COMMAND +``` -To use sopstool in your docker container, you can use the direct install method above, but since Docker 1.13, there is a better way by using build stages! +- `sopstool` is the entrypoint, so any sopstool subcommand can be run. +- `/work` is the default WORKDIR - this should be mounted to the root where `.sops.yml` is stored. +- the commands need access to your AWS credentials session to authenticate KMS. -In your Dockerfile: +Or, use as a install source in your Dockerfile. `sops` and `sopstool` are in `/usr/local/bin/`: ```docker -COPY --from=ibotta/sopstool:latest usr/local/bin/sops usr/local/bin/sopstool /usr/local/bin/ +COPY --from=ghcr.io/ibotta/sopstool:latest usr/local/bin/sops usr/local/bin/sopstool /usr/local/bin/ ``` -Images are tagged with the same version numbering as the releases, and `latest` always gets the latest release. Note that your image will need root CA certificates (typically installed with curl, or a `ca-certificates` package). +### Packages or binaries from Releases -To use sopstool in a docker container in other contexts (avoiding doing binary installs): +Check the [Releases](https://github.com/Ibotta/sopstool/releases) for the latest artifacts + +- Binaries (compressed as .tar.gz or .zip) (note, you will need `sops` installed manually) +- RPM, Debian and APK packages + +All artifacts have their sha256 checksums recorded in `sopstool_checksums.txt`, and SPDX SBOM artifacts are available. + +### Shell installer + +The most direct install uses a shell script hosted in this repository. This script will install the latest sops (if the command does not exist) and sopstool to `./bin` by default. ```sh -docker run --rm -v $(pwd):/work -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_REGION -e AWS_SECURITY_TOKEN -e AWS_SESSION_TOKEN ibotta/sopstool:latest $COMMAND +curl https://raw.githubusercontent.com/Ibotta/sopstool/main/install.sh | bash ``` -- `sopstool` is the entrypoint, so any sopstool subcommand can be run. -- `/work` is the default WORKDIR - this should be mounted to the root where `.sops.yml` is stored. -- the commands need access to your AWS credentials session to authenticate KMS. - -### Homebrew +- Override the sops version with the `-s` argument +- Override the sopstool version with the `-t` argument +- Override the binary install location with the `-b` argument + - remember, you may need `sudo` or root access if you are installing to `/usr/*` -Ibotta maintains a tap for their open-source projects, which includes sopstool. This will install sops as a requirement +Example with overrides: ```sh -brew install Ibotta/public/sopstool +curl https://raw.githubusercontent.com/Ibotta/sopstool/main/install.sh | bash -s -- -b /usr/local/bin -s 3.0.0 -t 0.3.0 ``` ### Installing sops manually -Since sopstool requires [sops](https://github.com/mozilla/sops), install it first. You can use one of the following methods: +sopstool requires [sops](https://github.com/mozilla/sops). You can use one of the following methods: + +- From one of the public repositories (it is available in most) +- From the [official releases](https://github.com/mozilla/sops/releases) #### Installing the sops binary with our script installer The install script above uses a separate script to download sops ```sh -curl https://raw.githubusercontent.com/Ibotta/sopstool/master/sopsinstall.sh | bash +curl https://raw.githubusercontent.com/Ibotta/sopstool/main/sopsinstall.sh | bash ``` - Override the tag with the first shell argument (defaults to latest) - Override the binary install location with the -b flag (defaults to `/.bin`) -(This script was generated by [godownloader](https://github.com/goreleaser/godownloader)) - #### Download sops from our https mirror -To avoid needing to find the 'latest' binary by hand or by script, use our https server to download the binary. The latest binary is uploaded automatically whenever sopstool is deployed. - -- Always the Latest - - Linux: [`https://oss-pkg.ibotta.com/sops/sops_linux.tar.gz`](https://oss-pkg.ibotta.com/sops/sops_linux.tar.gz) - - MacOS: [`https://oss-pkg.ibotta.com/sops/sops_darwin.tar.gz`](https://oss-pkg.ibotta.com/sops/sops_darwin.tar.gz) -- Versions: always the pattern: `https://oss-pkg.ibotta.com/sops/$TAG/sops_$OS.tar.gz` +To avoid needing to find the 'latest' binary by hand or by script, use our https server to download the binary. The latest binary is uploaded automatically whenever sopstool is deployed. The file has the pattern `sops_$OS_$ARCH`, except for `windows` -#### Download sops from github - -You can install it by hand [from a github release](https://github.com/mozilla/sops/releases). - -#### Installing sops using go (master branch) - -```sh -go get -u go.mozilla.org/sops/cmd/sops -``` +- OS: `linux`, `darwin` + - ARCH: `amd64`, `arm64` + - filenames: `sops_$OS_$ARCH.tar.gz` +- OS: `windows` + - ARCH `amd64` only + - filename: `sops_windows.zip` +- Versions + - latest: `https://oss-pkg.ibotta.com/sops/$filename` + - specific tags: `https://oss-pkg.ibotta.com/sops/$TAG/$filename` ### Installing sopstool manually Following the lead of [sops](https://github.com/mozilla/sops), we only build 64bit binaries. -### Installing the sopstool binary using our script installer +#### Installing the sopstool binary using our script installer The install script above uses a separate script to download sopstool ```sh -curl https://raw.githubusercontent.com/Ibotta/sopstool/master/sopstoolinstall.sh | bash +curl https://raw.githubusercontent.com/Ibotta/sopstool/main/sopstoolinstall.sh | bash ``` - Override the tag with the first shell argument (defaults to latest) - Override the binary install location with the -b flag (defaults to `/.bin`) -(This script was generated by [godownloader](https://github.com/goreleaser/godownloader)) - #### Download sopstool from our https mirror To avoid needing to find the 'latest' binary by hand or by script, use our https server to download the binary. The latest binary is uploaded automatically whenever sopstool is deployed. -- Always the Latest - - Linux: [`https://oss-pkg.ibotta.com/sopstool/sopstool_linux.tar.gz`](https://oss-pkg.ibotta.com/sopstool/sopstool_linux.tar.gz) - - MacOS: [`https://oss-pkg.ibotta.com/sopstool/sopstool_darwin.tar.gz`](https://oss-pkg.ibotta.com/sopstool/sopstool_darwin.tar.gz) -- Versions: always the pattern: `https://oss-pkg.ibotta.com/sopstool/$TAG/sopstool_$OS.tar.gz` - -#### Download sopstool from github - -Download the latest version for your platform from [a github release](https://github.com/Ibotta/sopstool/releases). +- OS: `linux`, `darwin` + - ARCH: `amd64`, `arm64` + - filenames: `sopstool_$OS_$ARCH.tar.gz` +- OS: `windows` + - ARCH: `amd64`, `arm64` + - filename: `sopstool_windows_$ARCH.zip` +- Versions + - latest: `https://oss-pkg.ibotta.com/sopstool/$filename` + - specific tags: `https://oss-pkg.ibotta.com/sopstool/$TAG/$filename` -### Installing sopstool using go (master branch) +Additionally, all other release assets are also within this folder. This includes the checksums, packages, sboms, as well as installers: -```sh -go get -u github.com/Ibotta/sopstool -``` +- `https://oss-pkg.ibotta.com/sopstool/install.sh` for the combined installer +- `https://oss-pkg.ibotta.com/sopstool/sopsinstall.sh` for the sops installer +- `https://oss-pkg.ibotta.com/sopstool/sopstoolinstall.sh` for the sopstool installer ## Usage @@ -171,7 +193,7 @@ sopstool completion --sh zsh ## How-To 1. Create a [KMS Key](https://aws.amazon.com/kms/). -1. Follow along the [Configuration Steps](https://github.com/Ibotta/sopstool/tree/master/#configuration), and place the `.sops.yaml` file at the root directory where your scripts will run. +1. Follow along the [Configuration Steps](https://github.com/Ibotta/sopstool/tree/main/#configuration), and place the `.sops.yaml` file at the root directory where your scripts will run. - All files added to SOPS are relative, or in child directories to the `.sops.yaml` configuration file. 1. Create a file to encrypt(any extension other than `.yaml` if you wish to do the **ENTIRE** file), or create a yaml file with `key: value` pairs(and make sure it's extension is `.yaml`). Sops will encrypt the values, but not it's keys. - You can read more about [SOPS Here](https://github.com/mozilla/sops). diff --git a/cmd/completion.go b/cmd/completion.go index e83916e..754dcbf 100644 --- a/cmd/completion.go +++ b/cmd/completion.go @@ -1,5 +1,5 @@ // Copyright © 2017 Ibotta -// https://github.com/spf13/cobra/blob/master/bash_completions.md. +// https://github.com/spf13/cobra/blob/main/bash_completions.md. package cmd diff --git a/cmd/docs.go b/cmd/docs.go index a5af768..8cf8b06 100644 --- a/cmd/docs.go +++ b/cmd/docs.go @@ -1,5 +1,5 @@ // Copyright © 2017 Ibotta -// https://github.com/spf13/cobra/blob/master/doc/md_docs.md +// https://github.com/spf13/cobra/blob/main/doc/md_docs.md package cmd diff --git a/docker-bake.hcl b/docker-bake.hcl new file mode 100644 index 0000000..d8bd94c --- /dev/null +++ b/docker-bake.hcl @@ -0,0 +1,40 @@ +variable "VERSION" { + default = "$VERSION" +} +variable "TAG" { + default = "$TAG" +} +variable "MAJOR" { + default = "$MAJOR" +} +variable "MINOR" { + default = "$MINOR" +} +variable "PATCH" { + default = "$PATCH" +} + +target "default" { + dockerfile = "Dockerfile" + tags = repo_tags([ + "latest", + "${lower(VERSION)}", + "${TAG}", + "v${MAJOR}.${MINOR}", + "v${MAJOR}" + ]) + labels = { + "org.label-schema.schema-version"="1.0", + "org.label-schema.version"="${MAJOR}.${MINOR}.${PATCH}", + "org.label-schema.name"="sopstool", + } + platforms = ["linux/amd64", "linux/arm64"] +} + +function "repo_tags" { + params = [tags] + result = concat( + formatlist("ghcr.io/ibotta/sopstool:%s", tags), + formatlist("ibotta/sopstool:%s", tags) + ) +} diff --git a/install.sh b/install.sh index 86ff525..c8d021e 100755 --- a/install.sh +++ b/install.sh @@ -8,39 +8,69 @@ usage() { $this: download binaries for sopstool -Usage: $this [bindir] - [bindir] sets bindir or installation directory, Defaults to ./bin +Usage: $this [-b bindir] [-o OS] [-a ARCH] [-s SOPS_VERSION] [-t SOPSTOOL_VERSION] [-d] [bindir] + -b sets bindir or installation directory, Defaults to ./bin + -o target OS (windows, linux, darwin) - uses uname by default + -a target architecture (amd64, arm64) - uses uname by default + -s SOPS_VERSION tag to download + -t SOPSTOOL_VERSION tag to download + -f force download to the binary directory even if command exists + -d turns on debug logging SOPS_VERSION overrides the sops version tag downloaded SOPSTOOL_VERSION overrides the sopstool version tag downloaded + [bindir] arg sets the installation directory - Consider setting GITHUB_TOKEN to avoid triggering GitHub rate limits. - See the following for more details: - https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/ - -Inspired by godownloader - https://github.com/goreleaser/godownloader + Flags are passed to the installers (-a, -o, -d) EOF exit 2 } parse_args() { - BINDIR=${1:-"./bin"} + BINDIR="${BINDIR:-./bin}" + while getopts "b:o:a:s:t:dfxh?" arg; do + case "${arg}" in + x) TARGET_X=1 && set -x ;; + b) BINDIR="${OPTARG}" ;; + o) TARGET_OS="${OPTARG}" ;; + a) TARGET_ARCH="${OPTARG}" ;; + s) SOPS_VERSION="${OPTARG}" ;; + t) SOPSTOOL_VERSION="${OPTARG}" ;; + f) FORCE=1 ;; + d) TARGET_DEBUG=1 ;; + h | \? | *) usage "$0" ;; + esac + done + shift $((OPTIND - 1)) + BINDIR=${1:-${BINDIR}} } execute() { - if ! is_command sops; then - http_exec https://raw.githubusercontent.com/Ibotta/sopstool/master/sopsinstall.sh -b "$BINDIR" "$SOPS_VERSION" + if [ -n "${TARGET_ARCH}" ]; then + set -- "$@" "-a" "${TARGET_ARCH}" + fi + if [ -n "${TARGET_OS}" ]; then + set -- "$@" "-o" "${TARGET_OS}" + fi + if [ -n "${TARGET_DEBUG}" ]; then + set -- "$@" "-d" + fi + if [ -n "${TARGET_X}" ]; then + set -- "$@" "-x" + fi + + if [ -n "${FORCE}" ] || ! is_command sops; then + http_exec https://raw.githubusercontent.com/Ibotta/sopstool/main/sopsinstall.sh -b "${BINDIR}" "$@" "${SOPS_VERSION}" fi - http_exec https://raw.githubusercontent.com/Ibotta/sopstool/master/sopstoolinstall.sh -b "$BINDIR" "$SOPSTOOL_VERSION" + http_exec https://raw.githubusercontent.com/Ibotta/sopstool/main/sopstoolinstall.sh -b "${BINDIR}" "$@" "${SOPSTOOL_VERSION}" echo "Both sops and sopstool installed" } http_exec() { - url=$1 + url="$1" shift if is_command curl; then cmd='curl --fail -sSL' diff --git a/main.go b/main.go index d626470..3fc234c 100644 --- a/main.go +++ b/main.go @@ -6,7 +6,7 @@ import "github.com/Ibotta/sopstool/cmd" // Goreleaser default is `-s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}`. var ( - version = "master" + version = "main" commit = "dirty" date = "Now" ) diff --git a/scripts/deploy-docker b/scripts/deploy-docker new file mode 100755 index 0000000..c64ba0e --- /dev/null +++ b/scripts/deploy-docker @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -e +set -o errexit +set -o nounset +set -o pipefail + +# enable interruption signal handling +trap - INT TERM + +REGEX="^v([0-9]+)\.([0-9]+)\.([0-9]+)" +export VERSION=$(jq -r '.version' dist/metadata.json) +export TAG=$(jq -r '.tag' dist/metadata.json) +if [[ "${TAG}" =~ ${REGEX} ]]; then + export MAJOR=${BASH_REMATCH[1]} + export MINOR=${BASH_REMATCH[2]} + export PATCH=${BASH_REMATCH[3]} +fi + +docker buildx bake --metadata-file dist/bake.json --sbom=true "$@" diff --git a/scripts/deploy b/scripts/deploy-sops similarity index 65% rename from scripts/deploy rename to scripts/deploy-sops index ce96a34..27dd378 100755 --- a/scripts/deploy +++ b/scripts/deploy-sops @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e set -o errexit set -o nounset @@ -17,11 +17,6 @@ if [ ! -e dist/sopstool_checksums.txt ]; then echo "Did not build checksums" && exit 1 fi -# also copy up installers -aws s3 cp sopsinstall.sh "$S3URL/sopstool/" -aws s3 cp sopstoolinstall.sh "$S3URL/sopstool/" -aws s3 cp install.sh "$S3URL/sopstool/" - # download sops for reupload to s3 SOPSDIST="dist/sops" if [ -d "$SOPSDIST" ]; then @@ -29,8 +24,11 @@ if [ -d "$SOPSDIST" ]; then fi mkdir -p "$SOPSDIST" -$DIR/sopsdownload.sh -o linux "$SOPSDIST" -$DIR/sopsdownload.sh -o darwin "$SOPSDIST" +$DIR/../sopsinstall.sh -o linux -a amd64 "$SOPSDIST" +$DIR/../sopsinstall.sh -o linux -a arm64 "$SOPSDIST" +$DIR/../sopsinstall.sh -o darwin -a amd64 "$SOPSDIST" +$DIR/../sopsinstall.sh -o darwin -a arm64 "$SOPSDIST" +$DIR/../sopsinstall.sh -o windows -a amd64 "$SOPSDIST" # put those on s3 aws s3 cp --recursive "$SOPSDIST/" "$S3URL/sops/" diff --git a/scripts/sopsdownload.sh b/scripts/sopsdownload.sh deleted file mode 100755 index fe95aeb..0000000 --- a/scripts/sopsdownload.sh +++ /dev/null @@ -1,339 +0,0 @@ -#!/bin/sh -set -e - -usage() { - this=$1 - cat </dev/null -} -echoerr() { - echo "$@" 1>&2 -} -log_prefix() { - echo "$0" -} -_logp=6 -log_set_priority() { - _logp="$1" -} -log_priority() { - if test -z "$1"; then - echo "$_logp" - return - fi - [ "$1" -le "$_logp" ] -} -log_tag() { - case $1 in - 0) echo "emerg" ;; - 1) echo "alert" ;; - 2) echo "crit" ;; - 3) echo "err" ;; - 4) echo "warning" ;; - 5) echo "notice" ;; - 6) echo "info" ;; - 7) echo "debug" ;; - *) echo "$1" ;; - esac -} -log_debug() { - log_priority 7 || return 0 - echoerr "$(log_prefix)" "$(log_tag 7)" "$@" -} -log_info() { - log_priority 6 || return 0 - echoerr "$(log_prefix)" "$(log_tag 6)" "$@" -} -log_err() { - log_priority 3 || return 0 - echoerr "$(log_prefix)" "$(log_tag 3)" "$@" -} -log_crit() { - log_priority 2 || return 0 - echoerr "$(log_prefix)" "$(log_tag 2)" "$@" -} -uname_os() { - os=$(uname -s | tr '[:upper:]' '[:lower:]') - case "$os" in - cygwin_nt*) os="windows" ;; - mingw*) os="windows" ;; - msys_nt*) os="windows" ;; - esac - echo "$os" -} -uname_arch() { - arch=$(uname -m) - case $arch in - x86_64) arch="amd64" ;; - x86) arch="386" ;; - i686) arch="386" ;; - i386) arch="386" ;; - aarch64) arch="arm64" ;; - armv5*) arch="armv5" ;; - armv6*) arch="armv6" ;; - armv7*) arch="armv7" ;; - esac - echo ${arch} -} -uname_os_check() { - os=$(uname_os) - case "$os" in - darwin) return 0 ;; - dragonfly) return 0 ;; - freebsd) return 0 ;; - linux) return 0 ;; - android) return 0 ;; - nacl) return 0 ;; - netbsd) return 0 ;; - openbsd) return 0 ;; - plan9) return 0 ;; - solaris) return 0 ;; - windows) return 0 ;; - esac - log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib" - return 1 -} -uname_arch_check() { - arch=$(uname_arch) - case "$arch" in - 386) return 0 ;; - amd64) return 0 ;; - arm64) return 0 ;; - armv5) return 0 ;; - armv6) return 0 ;; - armv7) return 0 ;; - ppc64) return 0 ;; - ppc64le) return 0 ;; - mips) return 0 ;; - mipsle) return 0 ;; - mips64) return 0 ;; - mips64le) return 0 ;; - s390x) return 0 ;; - amd64p32) return 0 ;; - esac - log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib" - return 1 -} -mktmpdir() { - test -z "$TMPDIR" && TMPDIR="$(mktemp -d)" - mkdir -p "${TMPDIR}" - echo "${TMPDIR}" -} -http_download_curl() { - local_file=$1 - source_url=$2 - header=$3 - if [ -z "$header" ]; then - code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url") - else - code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url") - fi - if [ "$code" != "200" ]; then - log_debug "http_download_curl received HTTP status $code" - return 1 - fi - return 0 -} -http_download_wget() { - local_file=$1 - source_url=$2 - header=$3 - if [ -z "$header" ]; then - wget -q -O "$local_file" "$source_url" - else - wget -q --header "$header" -O "$local_file" "$source_url" - fi -} -http_download() { - log_debug "http_download $2" - if is_command curl; then - http_download_curl "$@" - return - elif is_command wget; then - http_download_wget "$@" - return - fi - log_crit "http_download unable to find wget or curl" - return 1 -} -http_copy() { - tmp=$(mktemp) - http_download "${tmp}" "$1" "$2" || return 1 - body=$(cat "$tmp") - rm -f "${tmp}" - echo "$body" -} -github_release() { - owner_repo=$1 - version=$2 - test -z "$version" && version="latest" - giturl="https://github.com/${owner_repo}/releases/${version}" - json=$(http_copy "$giturl" "Accept:application/json") - test -z "$json" && return 1 - version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//') - test -z "$version" && return 1 - echo "$version" -} -hash_sha256() { - TARGET=${1:-/dev/stdin} - if is_command gsha256sum; then - hash=$(gsha256sum "$TARGET") || return 1 - echo "$hash" | cut -d ' ' -f 1 - elif is_command sha256sum; then - hash=$(sha256sum "$TARGET") || return 1 - echo "$hash" | cut -d ' ' -f 1 - elif is_command shasum; then - hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1 - echo "$hash" | cut -d ' ' -f 1 - elif is_command openssl; then - hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1 - echo "$hash" | cut -d ' ' -f a - else - log_crit "hash_sha256 unable to find command to compute sha-256 hash" - return 1 - fi -} -hash_sha256_verify() { - TARGET=$1 - checksums=$2 - if [ -z "$checksums" ]; then - log_err "hash_sha256_verify checksum file not specified in arg2" - return 1 - fi - BASENAME=${TARGET##*/} - want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1) - if [ -z "$want" ]; then - log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'" - return 1 - fi - got=$(hash_sha256 "$TARGET") - if [ "$want" != "$got" ]; then - log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got" - return 1 - fi -} -cat /dev/null </dev/null) || return 1 - echo "$hash" | cut -d ' ' -f 1 - elif is_command openssl; then - hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1 - echo "$hash" | cut -d ' ' -f a - else - log_crit "hash_sha256 unable to find command to compute sha-256 hash" - return 1 - fi -} -hash_sha256_verify() { - TARGET=$1 - checksums=$2 - if [ -z "$checksums" ]; then - log_err "hash_sha256_verify checksum file not specified in arg2" - return 1 - fi - BASENAME=${TARGET##*/} - want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1) - if [ -z "$want" ]; then - log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'" - return 1 - fi - got=$(hash_sha256 "$TARGET") - if [ "$want" != "$got" ]; then - log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got" - return 1 - fi -} cat /dev/null <