diff --git a/.github/workflows/_test-acceptance.tmpl.yaml b/.github/workflows/_test-acceptance.tmpl.yaml index 959e52f..2cacd95 100644 --- a/.github/workflows/_test-acceptance.tmpl.yaml +++ b/.github/workflows/_test-acceptance.tmpl.yaml @@ -3,6 +3,10 @@ name: Acceptance Test on: workflow_call: inputs: + project-name: + required: false + type: string + default: "vault-plugin-secrets-nexus-repository" vault-version: required: false type: string @@ -20,6 +24,8 @@ jobs: test: name: 'Test plugin on Vault v${{ inputs.vault-version }} + Nexus Repository v${{ inputs.nxr-version }}' runs-on: ubuntu-latest + permissions: + contents: write steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -42,11 +48,26 @@ jobs: file-install: false - name: Download plugin from build - if: github.action_ref != 'v*' + if: github.ref_type != 'tag' uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: - name: vault-plugin-secrets-nexus-repository - path: dist/bin + name: ${{ inputs.project-name }} + path: ${{ inputs.vault-plugin-dir }} + + - name: Download plugin from release + if: github.ref_type == 'tag' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VAULT_PLUGIN_DIR: ${{ inputs.vault-plugin-dir }} + PROJECT_NAME: ${{ inputs.project-name }} + VERSION: ${{ github.ref_name }} + run: | + set -euo pipefail + + gh release download "${VERSION}" -p "${PROJECT_NAME}_${VERSION}_linux-amd64.tar.gz" + tar xzf "${PROJECT_NAME}_${VERSION}_linux-amd64.tar.gz" + mkdir -p "${VAULT_PLUGIN_DIR}" + mv "${PROJECT_NAME}_${VERSION}" "${VAULT_PLUGIN_DIR}/${PROJECT_NAME}" - name: Run test shell: bash diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..925079e --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,154 @@ +name: Secure Release + +on: + push: + tags: + - "v*" # triggers only if push new tag version, like `v0.8.4` or else + +permissions: + contents: read + + +jobs: + goreleaser: + permissions: + contents: write # for goreleaser/goreleaser-action to create a GitHub release + runs-on: ubuntu-latest + outputs: + hashes: ${{ steps.hash.outputs.hashes }} + project-name: ${{ steps.hash.outputs.project-name }} + steps: + - name: Harden Runner + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 + with: + egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + + - name: Setup Go + uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + with: + go-version-file: ./go.mod + cache-dependency-path: ./go.sum + + - name: Run GoReleaser + id: run-goreleaser + uses: goreleaser/goreleaser-action@9ed2f89a662bf1735a48bc8557fd212fa902bebf # v6.1.0 + with: + args: release --clean + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GORELEASER_CURRENT_TAG: ${{ github.ref_name }} + + - name: Generate subject + id: hash + env: + ARTIFACTS: ${{ steps.run-goreleaser.outputs.artifacts }} + run: | + set -euo pipefail + + checksum_file="$(echo $ARTIFACTS | jq -r '.[] | select (.type=="Checksum") | .path')" + echo "hashes=$(cat $checksum_file | base64 -w0)" >> "$GITHUB_OUTPUT" + echo "project-name=$(echo $GITHUB_REPOSITORY | cut -d'/' -f2)" >> "$GITHUB_OUTPUT" + + provenance: + needs: [goreleaser] + permissions: + actions: read # To read the workflow path. + id-token: write # To sign the provenance. + contents: write # To add assets to a release. + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0 + with: + base64-subjects: "${{ needs.goreleaser.outputs.hashes }}" + provenance-name: "${{ needs.goreleaser.outputs.project-name }}_${{ github.ref_name }}.intoto.jsonl" + upload-assets: true # upload to a new release + draft-release: true + + verification: + needs: [goreleaser, provenance] + runs-on: ubuntu-latest + permissions: + contents: write # To download assets from draft release. + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + + - name: Install the verifier + uses: slsa-framework/slsa-verifier/actions/installer@3714a2a4684014deb874a0e737dffa0ee02dd647 # v2.6.0 + + - name: Download assets + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PROVENANCE: ${{ needs.provenance.outputs.provenance-name }} + PROJECT_NAME: ${{ needs.goreleaser.outputs.project-name }} + VERSION: ${{ github.ref_name }} + run: | + set -euo pipefail + gh release download "${VERSION}" -p "${PROJECT_NAME}_${VERSION}_*" + gh release download "${VERSION}" -p "${PROVENANCE}" + + - name: Verify assets + env: + CHECKSUMS: ${{ needs.goreleaser.outputs.hashes }} + PROVENANCE: "${{ needs.provenance.outputs.provenance-name }}" + run: | + set -euo pipefail + checksums="$(echo ${CHECKSUMS} | base64 -d)" + while read -r line; do + fn="$(echo ${line} | cut -d ' ' -f2)" + echo "Verifying ${fn}" + slsa-verifier verify-artifact --provenance-path "${PROVENANCE}" \ + --source-uri "github.com/${GITHUB_REPOSITORY}" \ + --source-tag "${VERSION}" \ + "${fn}" + done <<<"$checksums" + + acceptance-test: + needs: [ goreleaser, provenance ] + permissions: + contents: write # To download assets from draft release. + strategy: + matrix: + vault: [ "1.17.6", "1.18.2" ] + nexus: [ "3.73.0", "3.74.0" ] + uses: ./.github/workflows/_test-acceptance.tmpl.yaml + with: + vault-version: ${{ matrix.vault }} + nxr-version: ${{ matrix.nexus }} + vault-plugin-dir: ./dist/bin + + if-succeed-publish-release: + needs: [ verification, acceptance-test ] + permissions: + contents: write # To edit release. + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + + - name: Publish release + shell: bash + env: + VERSION: ${{ github.ref_name }} + run: | + set -euo pipefail + + PRE_RELEASE="true" + + # Only allow semver format: v0.2.3 v1.2.3 v10.2.3 + if [[ "${VERSION}" =~ ^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then + PRE_RELEASE="false" + fi + + gh release edit "${VERSION}" --draft=false --prerelease="${PRE_RELEASE}" + + # gh api --method POST \ + # -H "Accept: application/vnd.github+json" \ + # "/repos/${GITHUB_REPOSITORY}/releases/generate-notes" \ + # -f "tag_name=${VERSION}" | jq -r '.body' > release-notes.md + # + # gh release edit "${VERSION}" --draft=false --prerelease="${PRE_RELEASE}" --notes-file=release-notes.md diff --git a/.github/workflows/test-acceptance.yaml b/.github/workflows/test-acceptance.yaml index b317852..2ca3d0a 100644 --- a/.github/workflows/test-acceptance.yaml +++ b/.github/workflows/test-acceptance.yaml @@ -2,6 +2,7 @@ name: Acceptance Test on: push: + tags-ignore: '**' pull_request: @@ -48,6 +49,8 @@ jobs: path: dist/bin if-no-files-found: error test: + permissions: + contents: write needs: [ pre_job, build ] strategy: matrix: diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000..27dba26 --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,53 @@ +archives: + - format: tar.gz + name_template: >- + {{- .ProjectName }}_v + {{- .Version }}_ + {{- if eq .Os "darwin" }}macos + {{- else }}{{ .Os }}{{ end }}- + {{- if eq .Arch "amd64" }}amd64 + {{- else if eq .Arch "386" }}i386 + {{- else }}{{ .Arch }}{{ end }} + {{- if .Arm }}v{{ .Arm }}{{ end -}} + format_overrides: + - goos: windows + format: zip + files: + - README.md + - LICENSE + - '{{ .ProjectName }}_v{{ .Version }}_SHA256SUM.txt' +before: + hooks: + - go mod tidy +builds: + - binary: '{{ .ProjectName }}_v{{ .Version }}' + env: + - CGO_ENABLED=0 + main: './src/cmd/{{ .ProjectName }}/main.go' + flags: + - -trimpath + ldflags: + - '-s -w -X github.com/manhtukhang/{{ .ProjectName }}.Version=v{{ .Version }}' + goos: + - darwin + - linux + - freebsd + - windows + goarch: + - amd64 + - arm64 + mod_timestamp: '{{ .CommitTimestamp }}' + hooks: + post: |- + sh -c " + cd dist/{{ .ProjectName }}_{{ .Target }} &&\ + sha256sum {{ .ProjectName }}_v{{ .Version }}* > ../../{{ .ProjectName }}_v{{ .Version }}_SHA256SUM.txt + " +checksum: + algorithm: sha256 + name_template: '{{ .ProjectName }}_v{{ .Version }}_SHA256SUMS.txt' +changelog: + use: github-native +release: + draft: true + replace_existing_draft: true diff --git a/.slsa-goreleaser/darwin-amd64.yaml b/.slsa-goreleaser/darwin-amd64.yaml new file mode 100644 index 0000000..3addedb --- /dev/null +++ b/.slsa-goreleaser/darwin-amd64.yaml @@ -0,0 +1,13 @@ +version: 1 +env: + - CGO_ENABLED=0 +goos: darwin +goarch: amd64 +binary: "vault-plugin-secrets-nexus-repository_v{{ .Env.VERSION }}_{{ .Os }}-{{ .Arch }}" +main: "./src/cmd/vault-plugin-secrets-nexus-repository/main.go" +flags: + - -trimpath +ldflags: + - -s + - -w + - "-X github.com/manhtukhang/vault-plugin-secrets-nexus-repository.Version=v{{ .Env.VERSION }}" diff --git a/.slsa-goreleaser/darwin-arm64.yaml b/.slsa-goreleaser/darwin-arm64.yaml new file mode 100644 index 0000000..2a76c13 --- /dev/null +++ b/.slsa-goreleaser/darwin-arm64.yaml @@ -0,0 +1,13 @@ +version: 1 +env: + - CGO_ENABLED=0 +goos: darwin +goarch: arm64 +binary: "vault-plugin-secrets-nexus-repository_v{{ .Env.VERSION }}_{{ .Os }}-{{ .Arch }}" +main: "./src/cmd/vault-plugin-secrets-nexus-repository/main.go" +flags: + - -trimpath +ldflags: + - -s + - -w + - "-X github.com/manhtukhang/vault-plugin-secrets-nexus-repository.Version=v{{ .Env.VERSION }}" diff --git a/.slsa-goreleaser/linux-amd64.yaml b/.slsa-goreleaser/linux-amd64.yaml new file mode 100644 index 0000000..522db32 --- /dev/null +++ b/.slsa-goreleaser/linux-amd64.yaml @@ -0,0 +1,13 @@ +version: 1 +env: + - CGO_ENABLED=0 +goos: linux +goarch: amd64 +binary: "vault-plugin-secrets-nexus-repository_v{{ .Env.VERSION }}_{{ .Os }}-{{ .Arch }}" +main: "./src/cmd/vault-plugin-secrets-nexus-repository/main.go" +flags: + - -trimpath +ldflags: + - -s + - -w + - "-X github.com/manhtukhang/vault-plugin-secrets-nexus-repository.Version=v{{ .Env.VERSION }}" diff --git a/.slsa-goreleaser/linux-arm64.yaml b/.slsa-goreleaser/linux-arm64.yaml new file mode 100644 index 0000000..677e358 --- /dev/null +++ b/.slsa-goreleaser/linux-arm64.yaml @@ -0,0 +1,13 @@ +version: 1 +env: + - CGO_ENABLED=0 +goos: linux +goarch: arm64 +binary: "vault-plugin-secrets-nexus-repository_v{{ .Env.VERSION }}_{{ .Os }}-{{ .Arch }}" +main: "./src/cmd/vault-plugin-secrets-nexus-repository/main.go" +flags: + - -trimpath +ldflags: + - -s + - -w + - "-X github.com/manhtukhang/vault-plugin-secrets-nexus-repository.Version=v{{ .Env.VERSION }}" diff --git a/.slsa-goreleaser/windows-amd64.yaml b/.slsa-goreleaser/windows-amd64.yaml new file mode 100644 index 0000000..35f8624 --- /dev/null +++ b/.slsa-goreleaser/windows-amd64.yaml @@ -0,0 +1,13 @@ +version: 1 +env: + - CGO_ENABLED=0 +goos: windows +goarch: amd64 +binary: "vault-plugin-secrets-nexus-repository_v{{ .Env.VERSION }}_{{ .Os }}-{{ .Arch }}" +main: "./src/cmd/vault-plugin-secrets-nexus-repository/main.go" +flags: + - -trimpath +ldflags: + - -s + - -w + - "-X github.com/manhtukhang/vault-plugin-secrets-nexus-repository.Version=v{{ .Env.VERSION }}" diff --git a/.slsa-goreleaser/windows-arm64.yaml b/.slsa-goreleaser/windows-arm64.yaml new file mode 100644 index 0000000..a036d58 --- /dev/null +++ b/.slsa-goreleaser/windows-arm64.yaml @@ -0,0 +1,13 @@ +version: 1 +env: + - CGO_ENABLED=0 +goos: windows +goarch: arm64 +binary: "vault-plugin-secrets-nexus-repository_v{{ .Env.VERSION }}_{{ .Os }}-{{ .Arch }}" +main: "./src/cmd/vault-plugin-secrets-nexus-repository/main.go" +flags: + - -trimpath +ldflags: + - -s + - -w + - "-X github.com/manhtukhang/vault-plugin-secrets-nexus-repository.Version=v{{ .Env.VERSION }}"