diff --git a/.build/entrypoint.sh b/.build/entrypoint.sh new file mode 100644 index 00000000000..16d61c041cd --- /dev/null +++ b/.build/entrypoint.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# Copyright IBM Corp. 2016, 2025 +# SPDX-License-Identifier: BUSL-1.1 + +set -e + +fail() { + echo "$1" 1>&2 + exit 1 +} + +[[ -z "$GOARCH" ]] && fail "A GOARCH has not been defined" +[[ -z "$GITHUB_TOKEN" ]] && fail "A GITHUB_TOKEN has not been defined" + +host_arch="$(dpkg --print-architecture)" +host_arch="${host_arch##*-}" +if [[ "$host_arch" != "$GOARCH" ]]; then + # We're building for a different architecture than our target host OS so + # we have to tell the Go compiler to use the correct C cross-compiler for + # our target instead of relying on the host C compiler. + # + # https://packages.ubuntu.com/search?suite=noble§ion=all&arch=any&keywords=linux-gnu-gcc&searchon=contents + case "$GOARCH" in + amd64) + export CC=x86_64-linux-gnu-gcc + ;; + arm64) + export CC=aarch64-linux-gnu-gcc + ;; + s390x) + export CC=s390x-linux-gnu-gcc + ;; + *) + fail "Building for $GOARCH has not been implemented" + ;; + esac +fi + +# Install our tools if necessary +if ! ./tools.sh check-external; then + ./tools.sh install-external +fi + +# Assume that /build is where we've mounted the vault repo. +git config --global --add safe.directory /build +git config --global url."https://${GITHUB_TOKEN}@github.com".insteadOf "https://github.com" + +# Exec our command +cd build || exit 1 +exec "$@" diff --git a/.build/go.sh b/.build/go.sh new file mode 100644 index 00000000000..758ba0d7a18 --- /dev/null +++ b/.build/go.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# Copyright IBM Corp. 2016, 2025 +# SPDX-License-Identifier: BUSL-1.1 +set -e + +host_arch="$(dpkg --print-architecture)" +host_arch="${host_arch##*-}" +curl -L "https://go.dev/dl/go${GO_VERSION}.linux-${host_arch}.tar.gz" | tar -C /opt -zxv diff --git a/.build/system.sh b/.build/system.sh new file mode 100644 index 00000000000..6a9aa79b396 --- /dev/null +++ b/.build/system.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# Copyright IBM Corp. 2016, 2025 +# SPDX-License-Identifier: BUSL-1.1 + +set -e + +export DEBIAN_FRONTEND=noninteractive + +install() { + apt-get install -y "$@" +} + +# Install our cross building tools +# https://packages.ubuntu.com/search?suite=noble§ion=all&arch=any&keywords=crossbuild-essential&searchon=names + +apt-get update +apt-get install -y --no-install-recommends build-essential \ + gcc-s390x-linux-gnu \ + crossbuild-essential-s390x \ + ca-certificates \ + curl \ + git + +host_arch="$(dpkg --print-architecture)" +host_arch="${host_arch##*-}" +case "$host_arch" in + amd64) + install crossbuild-essential-arm64 gcc-aarch64-linux-gnu + ;; + arm64) + install gcc-x86-64-linux-gnu + ;; + *) + echo "Building on $host_arch has not been implemented" 1>&2 + exit 1 + ;; +esac + +# Clean up after ourselves for a minimal image +apt-get clean +rm -rf /var/lib/apt/lists/* diff --git a/.copywrite.hcl b/.copywrite.hcl index de148843b44..b4001d8315f 100644 --- a/.copywrite.hcl +++ b/.copywrite.hcl @@ -1,8 +1,9 @@ schema_version = 1 project { - license = "BUSL-1.1" - copyright_year = 2024 + license = "BUSL-1.1" + copyright_year = 2025 + copyright_holder = "IBM Corp." # (OPTIONAL) A list of globs that should not have copyright/license headers. # Supports doublestar glob patterns for more flexibility in defining which @@ -12,5 +13,8 @@ project { "ui/node_modules/**", "enos/modules/k8s_deploy_vault/raft-config.hcl", "plugins/database/postgresql/scram/**", + "enos/.enos/**", + "enos/k8s/.enos/**", + "enos/.terraform/**", ] } diff --git a/.github/.secret_scanning.yml b/.github/.secret_scanning.yml index 47005963047..7255c0ca923 100644 --- a/.github/.secret_scanning.yml +++ b/.github/.secret_scanning.yml @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. +# Copyright IBM Corp. 2016, 2025 # SPDX-License-Identifier: BUSL-1.1 paths-ignore: diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000000..46132393c86 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,109 @@ +# Each line is a file pattern followed by one or more owners. Being an owner +# means those groups or individuals will be added as reviewers to PRs affecting +# those areas of the code. +# +# More on CODEOWNERS files: https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners +# Default CODEOWNER primarily for contact purposes +* @hashicorp/vault + +# Select Auth engines are owned by Ecosystem +/builtin/credential/aws/ @hashicorp/vault-ecosystem +/builtin/credential/github/ @hashicorp/vault-ecosystem +/builtin/credential/ldap/ @hashicorp/vault-ecosystem +/builtin/credential/okta/ @hashicorp/vault-ecosystem + +# Secrets engines (pki, ssh, totp and transit omitted) +/builtin/logical/aws/ @hashicorp/vault-ecosystem +/builtin/logical/cassandra/ @hashicorp/vault-ecosystem +/builtin/logical/consul/ @hashicorp/vault-ecosystem +/builtin/logical/database/ @hashicorp/vault-ecosystem +/builtin/logical/mongodb/ @hashicorp/vault-ecosystem +/builtin/logical/mssql/ @hashicorp/vault-ecosystem +/builtin/logical/mysql/ @hashicorp/vault-ecosystem +/builtin/logical/nomad/ @hashicorp/vault-ecosystem +/builtin/logical/postgresql/ @hashicorp/vault-ecosystem +/builtin/logical/rabbitmq/ @hashicorp/vault-ecosystem + +# Identity Integrations (OIDC, tokens) +/vault/identity_store_oidc* @hashicorp/vault-ecosystem + +/plugins/ @hashicorp/vault-ecosystem +/vault/plugin_catalog.go @hashicorp/vault-ecosystem + +# Content on developer.hashicorp.com + +# Web presence gets notified of, and can approve changes to web tooling, but not content. + +/website/ @hashicorp/web-presence +/website/data/ +/website/public/ +/website/content/ + +# Education gets notified of, and can approve changes to web content. + +/website/data/ @hashicorp/vault-education-approvers +/website/public/ @hashicorp/vault-education-approvers +/website/content/ @hashicorp/vault-education-approvers +/website/templates/ @hashicorp/vault-education-approvers +/website/redirects.js @hashicorp/vault-education-approvers + +# Plugin docs +/website/content/docs/plugins/ @hashicorp/vault-ecosystem @hashicorp/vault-education-approvers +/website/content/docs/upgrading/plugins.mdx @hashicorp/vault-ecosystem @hashicorp/vault-education-approvers + +/ui/ @hashicorp/vault-ui +# UI code related to Vault's JWT/OIDC auth method and OIDC provider. +# Changes to these files often require coordination with backend code, +# so stewards of the backend code are added below for notification. +/ui/app/components/auth/form/oidc-jwt.ts @hashicorp/vault-ui @hashicorp/vault-ecosystem +/ui/app/components/auth/form/saml.ts @hashicorp/vault-ui @hashicorp/vault-ecosystem +/ui/app/routes/vault/cluster/oidc-*.js @hashicorp/vault-ui @hashicorp/vault-ecosystem + +# Release config; service account is required for automation tooling. +/.release/ @hashicorp/github-secure-vault-core @hashicorp/team-vault-quality +/.github/workflows/build.yml @hashicorp/github-secure-vault-core @hashicorp/team-vault-quality + +# Quality engineering +/.github/ @hashicorp/team-vault-quality +/enos/ @hashicorp/team-vault-quality + +# Cryptosec +/api/auth/cert/ @hashicorp/vault-crypto +/builtin/logical/pki/ @hashicorp/vault-crypto +/builtin/logical/pkiext/ @hashicorp/vault-crypto +/website/content/docs/secrets/pki/ @hashicorp/vault-crypto @hashicorp/vault-education-approvers +/website/content/api-docs/secret/pki/ @hashicorp/vault-crypto @hashicorp/vault-education-approvers +/website/content/api-docs/secret/pki.mdx @hashicorp/vault-crypto @hashicorp/vault-education-approvers +/builtin/credential/cert/ @hashicorp/vault-crypto +/website/content/docs/auth/cert.mdx @hashicorp/vault-crypto @hashicorp/vault-education-approvers +/website/content/api-docs/auth/cert.mdx @hashicorp/vault-crypto @hashicorp/vault-education-approvers +/builtin/logical/ssh/ @hashicorp/vault-crypto +/website/content/docs/secrets/ssh/ @hashicorp/vault-crypto @hashicorp/vault-education-approvers +/website/content/api-docs/secret/ssh.mdx @hashicorp/vault-crypto @hashicorp/vault-education-approvers +/builtin/logical/transit/ @hashicorp/vault-crypto +/website/content/docs/secrets/transit/ @hashicorp/vault-crypto @hashicorp/vault-education-approvers +/website/content/api-docs/secret/transit.mdx @hashicorp/vault-crypto @hashicorp/vault-education-approvers +/helper/random/ @hashicorp/vault-crypto +/sdk/helper/certutil/ @hashicorp/vault-crypto +/sdk/helper/cryptoutil/ @hashicorp/vault-crypto +/sdk/helper/kdf/ @hashicorp/vault-crypto +/sdk/helper/keysutil/ @hashicorp/vault-crypto +/sdk/helper/ocsp/ @hashicorp/vault-crypto +/sdk/helper/salt/ @hashicorp/vault-crypto +/sdk/helper/tlsutil/ @hashicorp/vault-crypto +/shamir/ @hashicorp/vault-crypto +/vault/barrier* @hashicorp/vault-crypto +/vault/managed_key* @hashicorp/vault-crypto +/vault/seal* @hashicorp/vault-crypto +/vault/seal/ @hashicorp/vault-crypto +/website/content/docs/configuration/seal/ @hashicorp/vault-crypto @hashicorp/vault-education-approvers +/website/content/docs/enterprise/sealwrap.mdx @hashicorp/vault-crypto @hashicorp/vault-education-approvers +/website/content/api-docs/system/sealwrap-rewrap.mdx @hashicorp/vault-crypto @hashicorp/vault-education-approvers +/website/content/docs/secrets/transform/ @hashicorp/vault-crypto @hashicorp/vault-education-approvers +/website/content/api-docs/secret/transform.mdx @hashicorp/vault-crypto @hashicorp/vault-education-approvers +/website/content/docs/secrets/kmip-profiles.mdx @hashicorp/vault-crypto @hashicorp/vault-education-approvers +/website/content/docs/secrets/kmip.mdx @hashicorp/vault-crypto @hashicorp/vault-education-approvers +/website/content/api-docs/secret/kmip.mdx @hashicorp/vault-crypto @hashicorp/vault-education-approvers +/website/content/docs/enterprise/fips/ @hashicorp/vault-crypto @hashicorp/vault-education-approvers +/website/content/docs/platform/k8s @hashicorp/vault-ecosystem @hashicorp/vault-education-approvers +/website/content/ @hashicorp/vault-customer-engineering @hashicorp/vault-education-approvers diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index d313527dcd8..b74b0e29cac 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. +# Copyright IBM Corp. 2016, 2025 # SPDX-License-Identifier: BUSL-1.1 contact_links: diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml deleted file mode 100644 index 281951c170b..00000000000 --- a/.github/actionlint.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: BUSL-1.1 - -self-hosted-runner: - # Labels of self-hosted runner in array of string - labels: - - small - - medium - - large - - ondemand - - disk_gb=64 - - os=linux - - type=m5.2xlarge - - type=c6a.xlarge - - type=c6a.4xlarge - - ubuntu-20.04 - - custom-linux-small-vault-latest - - custom-linux-medium-vault-latest - - custom-linux-xl-vault-latest diff --git a/.github/actionlint.yml b/.github/actionlint.yml new file mode 100644 index 00000000000..42c6e432a78 --- /dev/null +++ b/.github/actionlint.yml @@ -0,0 +1,20 @@ +# Copyright IBM Corp. 2016, 2025 +# SPDX-License-Identifier: BUSL-1.1 + +self-hosted-runner: + # Labels of self-hosted runner in array of string + labels: + - small + - medium + - large + - xlarge + - ondemand + - disk_gb=64 + - os=linux + - os=ubuntu-arm + - type=m5.2xlarge + - type=c6a.xlarge + - type=c6g.2xlarge + - type=c6a.4xlarge + - ubuntu-latest-x64 + - custom-linux-xl-vault-latest diff --git a/.github/actions/build-vault/action.yml b/.github/actions/build-vault/action.yml index a4ae210bbbb..bc2859a905c 100644 --- a/.github/actions/build-vault/action.yml +++ b/.github/actions/build-vault/action.yml @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. +# Copyright IBM Corp. 2016, 2025 # SPDX-License-Identifier: BUSL-1.1 --- @@ -11,59 +11,44 @@ description: | inputs: github-token: - type: string description: An elevated Github token to access private Go modules if necessary. default: "" cgo-enabled: - type: number description: Enable or disable CGO during the build. - default: 0 + default: "0" create-docker-container: - type: boolean description: Package the binary into a Docker/AWS container. - default: true + default: "true" create-redhat-container: - type: boolean description: Package the binary into a Redhat container. - default: false + default: "false" create-packages: - type: boolean description: Package the binaries into deb and rpm formats. - default: true + default: "true" goos: - type: string description: The Go GOOS value environment variable to set during the build. goarch: - type: string description: The Go GOARCH value environment variable to set during the build. goarm: - type: string description: The Go GOARM value environment variable to set during the build. default: "" goexperiment: - type: string description: Which Go experiments to enable. default: "" go-tags: - type: string description: A comma separated list of tags to pass to the Go compiler during build. default: "" package-name: - type: string description: The name to use for the linux packages. default: ${{ github.event.repository.name }} vault-binary-name: - type: string description: The name of the vault binary. default: vault vault-edition: - type: string description: The edition of vault to build. vault-version: - type: string description: The version metadata to inject into the build via the linker. web-ui-cache-key: - type: string description: The cache key for restoring the pre-built web UI artifact. outputs: @@ -74,24 +59,17 @@ outputs: runs: using: composite steps: - - name: Ensure zstd is available for actions/cache - # actions/cache restores based on cache key and "cache version", the former is unique to the - # build job or web UI, the latter is a hash which is based on the runner OS, the paths being - # cached, and the program used to compress it. Most of our workflows will use zstd to compress - # the cached artifact so we have to have it around for our machines to get both a version match - # and to decompress it. Most runners include zstd by default but there are exception like - # our Ubuntu 20.04 compatibility runners which do not. - shell: bash - run: which zstd || (sudo apt update && sudo apt install -y zstd) - - uses: ./.github/actions/set-up-go + - id: set-up-go + uses: ./.github/actions/set-up-go with: github-token: ${{ inputs.github-token }} + - uses: ./.github/actions/install-tools # sets env.VAULT_TOOLS_PATH - if: inputs.vault-edition != 'ce' name: Configure Git shell: bash run: git config --global url."https://${{ inputs.github-token }}:@github.com".insteadOf "https://github.com" - name: Restore UI from cache - uses: actions/cache@e12d46a63a90f2fae62d114769bbf2a179198b5c # v3.3.3 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: # Restore the UI asset from the UI build workflow. Never use a partial restore key. enableCrossOsArchive: true @@ -111,19 +89,39 @@ runs: if [[ '${{ inputs.vault-edition }}' =~ 'ce' ]]; then build_step_name='Vault ${{ inputs.goos }} ${{ inputs.goarch }} v${{ inputs.vault-version }}' package_version='${{ inputs.vault-version }}' + linux_package_license='BUSL-1.1' else build_step_name='Vault ${{ inputs.goos }} ${{ inputs.goarch }} v${{ inputs.vault-version }}+${{ inputs.vault-edition }}' package_version='${{ inputs.vault-version }}+ent' # this should always be +ent here regardless of enterprise edition + linux_package_license='IPLA' fi + # Generate a builder cache key that considers anything that might change + # our build container, including: + # - The Go version we're building with + # - External Go build tooling as defined in tools/tools.sh + # - The Dockerfile or .build directory + # - The build-vault Github action + docker_sha=$(git ls-tree HEAD Dockerfile --object-only --abbrev=5) + build_sha=$(git ls-tree HEAD .build --object-only --abbrev=5) + tools_sha=$(git ls-tree HEAD tools/tools.sh --object-only --abbrev=5) + github_sha=$(git ls-tree HEAD .github/actions/build-vault --object-only --abbrev=5) { echo "artifact-basename=$(make ci-get-artifact-basename)" echo "binary-path=dist/${{ inputs.vault-binary-name }}" echo "build-step-name=${build_step_name}" + echo "vault-builder-cache-key=${docker_sha}-${build_sha}-${tools_sha}-${github_sha}-$(cat .go-version)" echo "package-version=${package_version}" + echo "linux_package_license=${linux_package_license}" } | tee -a "$GITHUB_OUTPUT" - - name: ${{ steps.metadata.outputs.build-step-name }} + - if: inputs.vault-edition != 'ce' + id: build-vault-select-license + uses: hashicorp-forge/actions-pao-tool/select-license@6997f7457c338e008506005cc370e7b02f7fb421 # v1.0.3 + with: + arch: ${{ matrix.goarch }} + - if: inputs.cgo-enabled == '0' + name: ${{ steps.metadata.outputs.build-step-name }} env: - CGO_ENABLED: ${{ inputs.cgo-enabled }} + CGO_ENABLED: 0 GO_TAGS: ${{ inputs.go-tags }} GOARCH: ${{ inputs.goarch }} GOARM: ${{ inputs.goarm }} @@ -134,22 +132,99 @@ runs: VERSION_METADATA: ${{ inputs.vault-edition != 'ce' && inputs.vault-edition || '' }} shell: bash run: make ci-build + - if: inputs.cgo-enabled == '1' + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + with: + driver-opts: network=host # So we can run our own little registry + - if: inputs.cgo-enabled == '1' + shell: bash + run: docker run -d -p 5000:5000 --restart always --name registry registry:2 + - name: Build CGO builder image + if: inputs.cgo-enabled == '1' + id: build-push-action-attempt-1 + continue-on-error: true # we will retry this if it fails + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 + env: + DOCKER_BUILD_SUMMARY: false + with: + context: . + build-args: | + GO_VERSION=${{ steps.set-up-go.outputs.go-version }} + # Only build a container for the host OS since the same container + # handles cross building. + platforms: linux/amd64 + push: true + target: builder + tags: localhost:5000/vault-builder:${{ steps.metadata.outputs.vault-builder-cache-key }} + # Upload the resulting minimal image to actions cache. This could + # be a problem if the resulting images are too big. + cache-from: type=gha,scope=vault-builder-${{ steps.metadata.outputs.vault-builder-cache-key }} + cache-to: type=gha,mode=min,scope=vault-builder-${{ steps.metadata.outputs.vault-builder-cache-key }} + github-token: ${{ inputs.github-token }} + - name: Build CGO builder image + id: build-push-action-attempt-2 + continue-on-error: false + if: inputs.cgo-enabled == '1' && steps.build-push-action-attempt-1.outcome != 'success' + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 + env: + DOCKER_BUILD_SUMMARY: false + with: + context: . + build-args: | + GO_VERSION=${{ steps.set-up-go.outputs.go-version }} + # Only build a container for the host OS since the same container + # handles cross building. + platforms: linux/amd64 + push: true + target: builder + tags: localhost:5000/vault-builder:${{ steps.metadata.outputs.vault-builder-cache-key }} + # Upload the resulting minimal image to actions cache. This could + # be a problem if the resulting images are too big. + cache-from: type=gha,scope=vault-builder-${{ steps.metadata.outputs.vault-builder-cache-key }} + cache-to: type=gha,mode=min,scope=vault-builder-${{ steps.metadata.outputs.vault-builder-cache-key }} + github-token: ${{ inputs.github-token }} + - if: inputs.cgo-enabled == '1' + name: ${{ steps.metadata.outputs.build-step-name }} + shell: bash + run: | + mkdir -p dist + mkdir -p out + docker run \ + -v $(pwd):/build \ + -v ${VAULT_TOOLS_PATH}:/opt/tools/bin \ + -v $(go env GOMODCACHE):/go-mod-cache \ + --env GITHUB_TOKEN='${{ inputs.github-token }}' \ + --env CGO_ENABLED=1 \ + --env GO_TAGS='${{ inputs.go-tags }}' \ + --env GOARCH='${{ inputs.goarch }}' \ + --env GOARM='${{ inputs.goarm }}' \ + --env GOEXPERIMENT='${{ inputs.goexperiment }}' \ + --env GOMODCACHE=/go-mod-cache \ + --env GOOS='${{ inputs.goos }}' \ + --env VERSION='${{ inputs.version }}' \ + --env VERSION_METADATA='${{ inputs.vault-edition != 'ce' && inputs.vault-edition || '' }}' \ + localhost:5000/vault-builder:${{ steps.metadata.outputs.vault-builder-cache-key }} \ + make ci-build - if: inputs.vault-edition != 'ce' shell: bash - run: make ci-prepare-legal + run: make ci-prepare-ent-legal + env: + LICENSE_DIR: "${{ steps.build-vault-select-license.outputs.license-path }}/Softcopy" + - if: inputs.vault-edition == 'ce' + shell: bash + run: make ci-prepare-ce-legal - name: Bundle Vault env: BUNDLE_PATH: out/${{ steps.metadata.outputs.artifact-basename }}.zip shell: bash run: make ci-bundle - # Use actions/upload-artifact @3.x until https://hashicorp.atlassian.net/browse/HREL-99 is resolved - - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: ${{ steps.metadata.outputs.artifact-basename }}.zip path: out/${{ steps.metadata.outputs.artifact-basename }}.zip if-no-files-found: error - if: inputs.create-packages == 'true' - uses: hashicorp/actions-packaging-linux@v1 + uses: hashicorp/actions-packaging-linux@33f7d23b14f24e6a7b7d9948cb7f5caca2045ee3 with: name: ${{ inputs.package-name }} description: Vault is a tool for secrets management, encryption as a service, and privileged access management. @@ -157,7 +232,7 @@ runs: version: ${{ steps.metadata.outputs.package-version }} maintainer: HashiCorp homepage: https://github.com/hashicorp/vault - license: BUSL-1.1 + license: ${{ steps.metadata.outputs.linux_package_license }} binary: ${{ steps.metadata.outputs.binary-path }} deb_depends: openssl rpm_depends: openssl @@ -175,15 +250,13 @@ runs: echo "deb-files=$(basename out/*.deb)" } | tee -a "$GITHUB_OUTPUT" - if: inputs.create-packages == 'true' - # Use actions/upload-artifact @3.x until https://hashicorp.atlassian.net/browse/HREL-99 is resolved - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: ${{ steps.package-files.outputs.rpm-files }} path: out/${{ steps.package-files.outputs.rpm-files }} if-no-files-found: error - if: inputs.create-packages == 'true' - # Use actions/upload-artifact @3.x until https://hashicorp.atlassian.net/browse/HREL-99 is resolved - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: ${{ steps.package-files.outputs.deb-files }} path: out/${{ steps.package-files.outputs.deb-files }} diff --git a/.github/actions/changed-files/action.yml b/.github/actions/changed-files/action.yml index cde4feee0c2..a555b43b491 100644 --- a/.github/actions/changed-files/action.yml +++ b/.github/actions/changed-files/action.yml @@ -1,73 +1,46 @@ -# Copyright (c) HashiCorp, Inc. +# Copyright IBM Corp. 2016, 2025 # SPDX-License-Identifier: BUSL-1.1 --- -name: Determine what files changed between two git referecnes. +name: Determine what files have changed on either a pull request or commit. description: | - Determine what files have changed between two git references. If the github.event_type is - pull_request we'll compare the github.base_ref (merge target) and pull request head SHA. - For other event types we'll gather the changed files from the most recent commit. This allows - us to support PR and merge workflows. + Determine what files have changed on either a pull request or commit. + Writes the list of files to + +inputs: + github-token: + description: A preferred Github token to access private modules if necessary. outputs: - app-changed: - description: Whether or not the vault Go app was modified. - value: ${{ steps.changed-files.outputs.app-changed }} - docs-changed: - description: Whether or not the documentation was modified. - value: ${{ steps.changed-files.outputs.docs-changed }} - ui-changed: - description: Whether or not the web UI was modified. - value: ${{ steps.changed-files.outputs.ui-changed }} - files: - description: All of the file names that changed. - value: ${{ steps.changed-files.outputs.files }} + changed-files: + description: All of the files that changed. + value: ${{ steps.changed-files.outputs.changed-files }} runs: using: composite steps: - - id: ref + - id: changed-files-set-up-pipeline + name: Set up the pipeline tool + uses: ./.github/actions/set-up-pipeline + with: + github-token: ${{ inputs.github-token || github.token }} + - id: changed-files + name: Determine the changed files shell: bash - name: ref + env: + GITHUB_TOKEN: ${{ inputs.github-token || github.token }} run: | - # Determine our desired checkout ref. - # - # * If the trigger event is pull_request we will default to a magical merge SHA that Github - # creates. This SHA is the product of what merging our PR into the merge target branch at - # at the point in time when we created the PR. When you push a change to a PR branch - # Github updates this branch if it can. When you rebase a PR it updates this branch. - # - # * If the trigger event is pull_request and a `checkout-head` tag is present or the - # checkout-head input is set, we'll use HEAD of the PR branch instead of the magical - # merge SHA. - # - # * If the trigger event is a push (merge) then we'll get the latest commit that was pushed. - # - # * For anything any other event type we'll default to whatever is default in Github. + # Get a list of changed files and write the "changed-files" output to $GITHUB_OUTPUT if [ '${{ github.event_name }}' = 'pull_request' ]; then - checkout_ref='${{ github.event.pull_request.head.sha }}' - elif [ '${{ github.event_name }}' = 'push' ]; then - # Our checkout ref for any other event type should default to the github ref. - checkout_ref='${{ github.event.after && github.event.after || github.event.push.after }}' + pipeline github list changed-files \ + --owner hashicorp \ + --repo '${{ github.event.pull_request.head.repo.name }}' \ + --pr '${{ github.event.pull_request.number }}' \ + --github-output else - checkout_ref='${{ github.ref }}' + pipeline github list changed-files \ + --owner hashicorp \ + --repo '${{ github.event.repository.name }}' \ + --commit '${{ github.event.after && github.event.after || github.event.push.after && github.event.push.after || github.sha }}' \ + --github-output fi - echo "ref=${checkout_ref}" | tee -a "$GITHUB_OUTPUT" - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - repository: ${{ github.repository }} - path: "changed-files" - # The fetch-depth could probably be optimized at some point. It's currently set to zero to - # ensure that we have a successfull diff, regardless of how many commits might be present - # present between the two references we're comparing. It would be nice to change this - # depending on the number of commits by using the push.commits and/or pull_request.commits - # payload fields, however, they have different behavior and limitations. For now we'll do - # the slow but sure thing of getting the whole repository. - fetch-depth: 0 - ref: ${{ steps.ref.outputs.ref }} - - id: changed-files - name: changed-files - # This script writes output values to $GITHUB_OUTPUT and STDOUT - shell: bash - run: ./.github/scripts/changed-files.sh ${{ github.event_name }} ${{ github.ref_name }} ${{ github.base_ref }} - working-directory: changed-files diff --git a/.github/actions/checkout/action.yml b/.github/actions/checkout/action.yml index 35cc1fd4cee..791f2d2fb3b 100644 --- a/.github/actions/checkout/action.yml +++ b/.github/actions/checkout/action.yml @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. +# Copyright IBM Corp. 2016, 2025 # SPDX-License-Identifier: BUSL-1.1 --- @@ -70,7 +70,7 @@ runs: echo "ref=${checkout_ref}" echo "depth=${fetch_depth}" } | tee -a "$GITHUB_OUTPUT" - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: path: ${{ inputs.path }} fetch-depth: ${{ steps.ref.outputs.depth }} diff --git a/.github/actions/containerize/action.yml b/.github/actions/containerize/action.yml index 91c67c9dfbc..a61dcdb8c27 100644 --- a/.github/actions/containerize/action.yml +++ b/.github/actions/containerize/action.yml @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. +# Copyright IBM Corp. 2016, 2025 # SPDX-License-Identifier: BUSL-1.1 --- @@ -10,31 +10,24 @@ description: | inputs: docker: - type: boolean description: | Package the binary into a Docker container suitable for the Docker and AWS registries. We'll automatically determine the correct tags and target depending on the vault edition. - default: true + default: 'true' goarch: - type: string description: The Go GOARCH value environment variable to set during the build. goos: - type: string description: The Go GOOS value environment variable to set during the build. redhat: - type: boolean description: Package the binary into a UBI container suitable for the Redhat Quay registry. - default: false + default: 'false' vault-binary-path: - type: string description: The path to the vault binary. default: dist/vault vault-edition: - type: string description: The edition of vault to build. default: ce vault-version: - type: string description: The vault version. outputs: @@ -45,40 +38,78 @@ outputs: runs: using: composite steps: + - if: inputs.vault-edition != 'ce' && (inputs.docker == 'true' || inputs.redhat == 'true') + uses: hashicorp-forge/actions-pao-tool/select-license@6997f7457c338e008506005cc370e7b02f7fb421 # v1.0.3 + id: build-vault-select-license + with: + arch: ${{ matrix.goarch }} - id: vars shell: bash run: | - if [[ '${{ inputs.vault-edition }}' =~ 'ce' ]]; then - # CE containers - container_version='${{ inputs.vault-version }}' - docker_container_tags='docker.io/hashicorp/vault:${{ inputs.vault-version }} public.ecr.aws/hashicorp/vault:${{ inputs.vault-version }}' - docker_container_target='default' - redhat_container_tags='quay.io/redhat-isv-containers/5f89bb5e0b94cf64cfeb500a:${{ inputs.vault-version }}-ubi' - redhat_container_target='ubi' - else - # Ent containers - container_version='${{ inputs.vault-version }}+${{ inputs.vault-edition }}' - - if [[ '${{ inputs.vault-edition }}' =~ 'fips' ]]; then - # Ent FIPS 140-2 containers - docker_container_tags='docker.io/hashicorp/vault-enterprise-fips:${{ inputs.vault-version }}-${{ inputs.vault-edition }} public.ecr.aws/hashicorp/vault-enterprise-fips:${{ inputs.vault-version }}-${{ inputs.vault-edition }}' - docker_container_target='ubi-fips' - redhat_container_tags='quay.io/redhat-isv-containers/6283f645d02c6b16d9caeb8e:${{ inputs.vault-version }}-${{ inputs.vault-edition }}-ubi' - redhat_container_target='ubi-fips' - else - # All other Ent containers + case '${{ inputs.vault-edition }}' in + "ce") + container_version='${{ inputs.vault-version }}' + docker_container_tags='docker.io/hashicorp/vault:${{ inputs.vault-version }} public.ecr.aws/hashicorp/vault:${{ inputs.vault-version }}' + docker_container_target='default' + redhat_container_tags='quay.io/redhat-isv-containers/5f89bb5e0b94cf64cfeb500a:${{ inputs.vault-version }}-ubi' + redhat_container_target='ubi' + license_source='LICENSE' + license_dest='/usr/share/doc/vault/LICENSE.txt' + ;; + "ent") + container_version='${{ inputs.vault-version }}+${{ inputs.vault-edition }}' docker_container_tags='docker.io/hashicorp/vault-enterprise:${{ inputs.vault-version }}-${{ inputs.vault-edition}} public.ecr.aws/hashicorp/vault-enterprise:${{ inputs.vault-version }}-${{ inputs.vault-edition }}' docker_container_target='default' redhat_container_tags='quay.io/redhat-isv-containers/5f89bb9242e382c85087dce2:${{ inputs.vault-version }}-${{ inputs.vault-edition }}-ubi' redhat_container_target='ubi' - fi - fi + license_source='${{ steps.build-vault-select-license.outputs.license-path }}/Softcopy' + license_dest='/usr/share/doc/vault/Softcopy/' + ;; + "ent.hsm") + container_version='${{ inputs.vault-version }}+${{ inputs.vault-edition }}' + docker_container_tags='docker.io/hashicorp/vault-enterprise:${{ inputs.vault-version }}-${{ inputs.vault-edition}} public.ecr.aws/hashicorp/vault-enterprise:${{ inputs.vault-version }}-${{ inputs.vault-edition }}' + docker_container_target='ubi-hsm' + redhat_container_tags='quay.io/redhat-isv-containers/5f89bb9242e382c85087dce2:${{ inputs.vault-version }}-${{ inputs.vault-edition }}-ubi' + redhat_container_target='ubi-hsm' + license_source='${{ steps.build-vault-select-license.outputs.license-path }}/Softcopy' + license_dest='/usr/share/doc/vault/Softcopy/' + ;; + "ent.hsm.fips1403") + container_version='${{ inputs.vault-version }}+${{ inputs.vault-edition }}' + docker_container_tags='docker.io/hashicorp/vault-enterprise:${{ inputs.vault-version }}-${{ inputs.vault-edition}} public.ecr.aws/hashicorp/vault-enterprise:${{ inputs.vault-version }}-${{ inputs.vault-edition }}' + docker_container_target='ubi-hsm-fips' + redhat_container_tags='quay.io/redhat-isv-containers/5f89bb9242e382c85087dce2:${{ inputs.vault-version }}-${{ inputs.vault-edition }}-ubi' + redhat_container_target='ubi-hsm-fips' + license_source='${{ steps.build-vault-select-license.outputs.license-path }}/Softcopy' + license_dest='/usr/share/doc/vault/Softcopy/' + ;; + "ent.fips1403") + # NOTE: For compatibility we still publish the ent.fips1403 containers to different + # namespaces. All ent, ent.hsm, and ent.hsm.fips1403 containers are released in the + # enterprise namespaces. After we've updated the upstream docker action to support + # multiple tags we can start to tag images with both namespaces, publish to both, and + # eventually sunset the fips1403 specific namespaces. + container_version='${{ inputs.vault-version }}+${{ inputs.vault-edition }}' + docker_container_tags='docker.io/hashicorp/vault-enterprise-fips:${{ inputs.vault-version }}-${{ inputs.vault-edition }} public.ecr.aws/hashicorp/vault-enterprise-fips:${{ inputs.vault-version }}-${{ inputs.vault-edition }}' + docker_container_target='ubi-fips' + redhat_container_tags='quay.io/redhat-isv-containers/6283f645d02c6b16d9caeb8e:${{ inputs.vault-version }}-${{ inputs.vault-edition }}-ubi' + redhat_container_target='ubi-fips' + license_source='${{ steps.build-vault-select-license.outputs.license-path }}/Softcopy' + license_dest='/usr/share/doc/vault/Softcopy/' + ;; + *) + echo "Cannot generate container tags for unknown vault edition: ${{ inputs.vault-edition }}" 2>&1 + exit 1 + ;; + esac { echo "container-version=${container_version}" echo "docker-container-tags=${docker_container_tags}" echo "docker-container-target=${docker_container_target}" echo "redhat-container-tags=${redhat_container_tags}" echo "redhat-container-target=${redhat_container_target}" + echo "license_source=${license_source}" + echo "license_dest=${license_dest}" echo "revision=$(make ci-get-revision)" } | tee -a "$GITHUB_OUTPUT" - if: inputs.docker == 'true' || inputs.redhat == 'true' @@ -90,20 +121,28 @@ runs: [[ ! -d "$dest_dir" ]] && mkdir -p "$dest_dir" [[ ! -f "$dest_path" ]] && cp ${{ inputs.vault-binary-path }} "${dest_path}" - if: inputs.docker == 'true' - uses: hashicorp/actions-docker-build@v1 + uses: hashicorp/actions-docker-build@ryan/VAULT-34830-allow-repo-configuration with: arch: ${{ inputs.goarch }} do_zip_extract_step: 'false' # Don't download and extract an already present binary - target: ${{ steps.vars.outputs.docker-container-target }} - tags: ${{ steps.vars.outputs.docker-container-tags }} + extra_build_args: | + LICENSE_SOURCE=${{ steps.vars.outputs.license_source }} + LICENSE_DEST=${{ steps.vars.outputs.license_dest }} + repo_name: ${{ inputs.vault-edition == 'ce' && 'vault' || 'vault-enterprise' }} revision: ${{ steps.vars.outputs.revision }} + tags: ${{ steps.vars.outputs.docker-container-tags }} + target: ${{ steps.vars.outputs.docker-container-target }} version: ${{ steps.vars.outputs.container-version }} - if: inputs.redhat == 'true' - uses: hashicorp/actions-docker-build@v1 + uses: hashicorp/actions-docker-build@ryan/VAULT-34830-allow-repo-configuration with: arch: ${{ inputs.goarch }} do_zip_extract_step: 'false' # Don't download and extract an already present binary + extra_build_args: | + LICENSE_SOURCE=${{ steps.vars.outputs.license_source }} + LICENSE_DEST=${{ steps.vars.outputs.license_dest }} redhat_tag: ${{ steps.vars.outputs.redhat-container-tags }} - target: ${{ steps.vars.outputs.redhat-container-target }} + repo_name: ${{ inputs.vault-edition == 'ce' && 'vault' || 'vault-enterprise' }} revision: ${{ steps.vars.outputs.revision }} + target: ${{ steps.vars.outputs.redhat-container-target }} version: ${{ steps.vars.outputs.container-version }} diff --git a/.github/actions/create-dynamic-config/action.yml b/.github/actions/create-dynamic-config/action.yml new file mode 100644 index 00000000000..aff1cb2501b --- /dev/null +++ b/.github/actions/create-dynamic-config/action.yml @@ -0,0 +1,59 @@ +# Copyright IBM Corp. 2016, 2025 +# SPDX-License-Identifier: BUSL-1.1 + +--- +name: Create dynamic pipeline configuration +description: Create dynamic test configuration by restoring existing valid config or creating new config + +inputs: + github-token: + description: An elevated Github token to access private HashiCorp modules. + vault-edition: + description: The vault edition to use when generating the dynamic config + vault-version: + description: The vault version to use when generating the dynamic config + +runs: + using: composite + steps: + - name: dyn-cfg-metadata + id: dyn-cfg-metadata + shell: bash + run: | + # Since the dynamic config is created by a specific version of the + # pipeline tool, we always need to factor it into our cache key. + # If the pipeline changes we always want to make sure we are using + # dynamic config from the latest version. + # + # We use a weekly date in the cache key so that we regenerate the + # configuration on at least a weekly basis + # + # If/when Github decides to purge our tiny config file cache we'll also + # recreate it as necessary. + # + # Uses GITHUB_ENV instead of GITHUB_OUTPUT because composite actions are broken, + # see: https://github.com/actions/cache/issues/803#issuecomment-1793565071 + { + echo "DYNAMIC_CONFIG_KEY=${{ inputs.vault-version }}-$(date +%Y-%m-%U)-$(git ls-tree HEAD tools/pipeline --object-only --abbrev=8)" + echo "DYNAMIC_CONFIG_PATH=enos/enos-dynamic-config.hcl" + } | tee -a "$GITHUB_ENV" + - name: Try to restore dynamic config from cache + id: dyn-cfg-cache + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: ${{ env.DYNAMIC_CONFIG_PATH }} + key: dyn-cfg-${{ env.DYNAMIC_CONFIG_KEY }} + - if: steps.dyn-cfg-cache.outputs.cache-hit != 'true' + id: dyn-cfg-set-up-pipeline + # If we can't restore it from config then set up pipeline and generate it + name: Set up the pipeline tool + uses: ./.github/actions/set-up-pipeline + with: + github-token: ${{ inputs.github-token }} + - if: steps.dyn-cfg-cache.outputs.cache-hit != 'true' + id: dyn-cfg-generate + name: Create dynamic configuration + shell: bash + run: | + # Make sure that any branch specific dynamic config has been generated + pipeline generate enos-dynamic-config -d ./enos --file enos-dynamic-config.hcl -v ${{ inputs.vault-version }} -e ${{ inputs.vault-edition }} -n 3 --log debug diff --git a/.github/actions/install-external-tools/action.yml b/.github/actions/install-external-tools/action.yml deleted file mode 100644 index e41fddad278..00000000000 --- a/.github/actions/install-external-tools/action.yml +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: BUSL-1.1 - ---- -name: Install external tools for CI -description: Install external tools CI - -# When possible, prefer installing pre-built external tools for speed. This allows us to avoid -# downloading modules and compiling external tools on CI runners. - -runs: - using: composite - steps: - - uses: ./.github/actions/set-up-buf - with: - version: v1.25.0 # This should match the version in tools/tool.sh - - uses: ./.github/actions/set-up-gofumpt - - uses: ./.github/actions/set-up-gosimports - - uses: ./.github/actions/set-up-gotestsum - - uses: ./.github/actions/set-up-misspell - - uses: ./.github/actions/set-up-staticcheck - # We assume that the Go toolchain will be managed by the caller workflow so we don't set one - # up here. - - run: go install google.golang.org/protobuf/cmd/protoc-gen-go@latest - shell: bash - - run: go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest - shell: bash - - run: go install github.com/favadi/protoc-go-inject-tag@latest - shell: bash - - run: go install golang.org/x/tools/cmd/goimports@latest - shell: bash - - run: go install github.com/golangci/revgrep/cmd/revgrep@latest - shell: bash diff --git a/.github/actions/install-tools/action.yml b/.github/actions/install-tools/action.yml new file mode 100644 index 00000000000..5aa4b970547 --- /dev/null +++ b/.github/actions/install-tools/action.yml @@ -0,0 +1,89 @@ +# Copyright IBM Corp. 2016, 2025 +# SPDX-License-Identifier: BUSL-1.1 + +--- +name: Install all of the developer tools +description: | + Install all of the developer tools that are defined in tools/tools.sh. When + possible we'll restore the tools from prior build that was cached. On a cache + miss we'll rebuild the tools. After the tools are restored the `cache-path` + will be added to the GITHUB_PATH. + +inputs: + no-restore: + description: Whether or not to restore the Go module cache on a cache hit + default: "false" + no-save: + description: Whether or not to create a Go module cache on cache miss + default: "false" + destination: + description: "Where to install the tools (default: $HOME/bin/vault-tools)" + default: "$HOME/bin/vault-tools" + +runs: + using: composite + steps: + - id: metadata + shell: bash + run: | + # Create the tool cache directory if it doesn't exist and add it to the + # GITHUB_PATH to make them available to other actions. + mkdir -p "${{ inputs.destination }}" + destination="$(readlink -f "${{ inputs.destination }}")" + echo "${destination}" >> "$GITHUB_PATH" + + # actions/cache restore has some surprising relative pathing behavior we + # need to deal with. When it restores something it does it relative to + # the check working directory. Since that can be different depending on + # our self-hosted vs Github hosted runners, i.e. + # /home/runner/actions-runner/_work vs. /home/runner/work + # we need to factor in the absolute path of our working directory in our + # cache key. If we don't then caches created on one runner type will be + # incompatible on the other. + # + # See: https://github.com/actions/cache/issues/1127 + wd_hash=$(realpath . | sha256sum | head -c 7) + + # Caches automatically prevent cross distro but not cross arch. We'll + # include the os and arch in the key to make it easy to grok which cache + # is for which platform. + os="$(echo "$RUNNER_OS" | tr '[:upper:]' '[:lower:]')" + arch="$(echo "$RUNNER_ARCH" | tr '[:upper:]' '[:lower:]')" + if [ "${arch}" = "x64" ]; then + arch="amd64" + fi + + # Hash the tools directory so that we update our cache automatically + # if a dep caches. + tools_hash=$(git ls-tree HEAD tools --object-only | head -c 7) + + # Build the unique cache key + cache_key="tools-${os}-${arch}-${wd_hash}-${tools_hash}" + + # Use GITHUB_ENV instead of GITHUB_OUTPUT because composite actions are + # broken if you embed them into another composite actions. + # + # See: https://github.com/actions/cache/issues/803#issuecomment-1793565071 + { + echo "VAULT_TOOLS_PATH=${destination}" + echo "VAULT_TOOLS_CACHE_KEY=${cache_key}" + } | tee -a "$GITHUB_ENV" + - id: cache-tools + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + lookup-only: ${{ inputs.no-restore }} + path: ${{ env.VAULT_TOOLS_PATH }} + key: ${{ env.VAULT_TOOLS_CACHE_KEY }} + - if: steps.cache-tools.outputs.cache-hit != 'true' && inputs.no-save != 'true' + name: Install tools + shell: bash + env: + GOPRIVATE: github.com/hashicorp/* + # `go install` to our vault tool cache + GOBIN: ${{ env.VAULT_TOOLS_PATH }} + # Don't use the global mod cache because we don't want to pollute it + # with tool modules. + GOMODCACHE: /home/runner/.cache/vault-tool-mod-cache + run: | + make tools + du -h -d 1 ${{ env.VAULT_TOOLS_PATH }} diff --git a/.github/actions/metadata/action.yml b/.github/actions/metadata/action.yml index 53eff3d62c9..62e7ee2e318 100644 --- a/.github/actions/metadata/action.yml +++ b/.github/actions/metadata/action.yml @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. +# Copyright IBM Corp. 2016, 2025 # SPDX-License-Identifier: BUSL-1.1 --- @@ -11,6 +11,8 @@ description: | to maintain compatibility in both execution contexts. inputs: + github-token: + description: An elevated Github token to use for searching labels vault-version: description: | The version of vault from hashicorp/action-set-product-version. If set we'll utilize this @@ -22,9 +24,6 @@ outputs: compute-build: description: A JSON encoded "runs-on" for App build worfkflows. value: ${{ steps.workflow-metadata.outputs.compute-build }} - compute-build-compat: - description: A JSON encoded "runs-on" for App build workflows that need an older glibc to link against. - value: ${{ steps.workflow-metadata.outputs.compute-build-compat }} compute-build-ui: description: A JSON encoded "runs-on" for web UI build workflows. value: ${{ steps.workflow-metadata.outputs.compute-build-ui }} @@ -40,12 +39,18 @@ outputs: go-tags: description: The minimal set of Go tags required to build the correct edition of Vault. value: ${{ steps.workflow-metadata.outputs.go-tags }} + is-ce-in-enterprise: + description: Whether or not the workflow is running CE Vault in the context of Vault Enterprise. + value: ${{ steps.workflow-metadata.outputs.is-ce-in-enterprise }} is-draft: description: Whether or not the workflow is executing in the context of a pull request draft. value: ${{ steps.workflow-metadata.outputs.is-draft }} - is-enterprise: - description: Whether or not the workflow is executing in the context of Vault enterprise. - value: ${{ steps.workflow-metadata.outputs.is-enterprise }} + is-ent-branch: + description: Whether or not the workflow is executing in the context of Vault Enterprise. + value: ${{ steps.workflow-metadata.outputs.is-ent-branch }} + is-ent-repo: + description: Whether or not the workflow is executing in the context of hashicorp/vault-enterprise + value: ${{ steps.workflow-metadata.outputs.is-ent-repo }} is-fork: description: Whether or not the workflow is being triggered on a pull request that is a fork. value: ${{ steps.workflow-metadata.outputs.is-fork }} @@ -97,25 +102,44 @@ runs: name: workflow-metadata shell: bash env: - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ inputs.github-token || github.token }} run: | if [ '${{ github.event_name }}' = 'pull_request' ]; then is_draft='${{ github.event.pull_request.draft }}' - # Determine our labels. If our event type is pull_request this is rather straight forward. If - # our even_type is push (merge) we'll need to look up the pull request associated with the - # commit and get the labels. This will return the label names as an array. - labels=$(jq -rc <<< '${{ toJSON(github.event.pull_request.labels.*.name) }}') + # Determine our pull request labels. We specifically look them up via the pulls API + # because the github.event.pull_request.labels.*.name context is very inflexible. + # This allows people to add labels after inital pull request and/or to re-run this + # workflow to reload them. + labels=$(gh api "/repos/${{ github.repository }}/issues/${{ github.event.number }}/labels" | jq -erc '. | map(.name)') else + # We can assume we're being triggered for a 'push' (a merge) is_draft='false' - # Look up the labels for the pull request that is associated with the last commit. If - # there are none set it as a JSON encoded empty array. - if pr_number=$(gh api "/repos/${{ github.repository }}/commits/${{ github.ref }}/pulls" | jq -erc '.[0].number'); then - if ! labels=$(gh api "/repos/${{ github.repository }}/issues/${pr_number}/labels" | jq -erc '. | map(.name)'); then - labels='[]' - fi - else + # Look up the pull request labels for the PR that is associated with + # the commit. If there are none set it as a JSON encoded empty array. + repo=$(printf ${{ github.repository }} | cut -d "/" -f2) + if ! labels=$(gh api graphql -F repo="$repo" -F sha="${{ steps.vault-metadata.outputs.vault-revision }}" -f query=' + query($repo: String!, $sha: String!){ + repository(name: $repo, owner: "hashicorp") { + commit: object(expression: $sha) { + ... on Commit { + associatedPullRequests(first:1){ + edges{ + node{ + labels(first: 10) { + nodes { + name + } + } + } + } + } + } + } + } + }' | jq -erc '.data.repository.commit.associatedPullRequests.edges[0].node.labels.nodes | map(.name)'); + then labels='[]' fi fi @@ -127,30 +151,47 @@ runs: echo "workflow-trigger=${{ github.event_name }}" } | tee -a "$GITHUB_OUTPUT" - # Set CE and Ent specific workflow metadata - is_enterprise='${{ contains(github.repository, 'vault-enterprise') }}' - if [ "$is_enterprise" = 'true' ]; then - { - echo 'compute-build=["self-hosted","ondemand","os=linux","disk_gb=64","type=c6a.4xlarge"]' - echo 'compute-build-compat=["self-hosted","ubuntu-20.04"]' # for older glibc compatibility, m6a.4xlarge - echo 'compute-build-ui=["self-hosted","ondemand","os=linux", "disk_gb=64", "type=c6a.2xlarge"]' - echo 'compute-test-go=["self-hosted","ondemand","os=linux","disk_gb=64","type=c6a.2xlarge"]' - echo 'compute-test-ui=["self-hosted","ondemand","os=linux","type=m6a.2xlarge"]' - echo 'compute-small=["self-hosted","linux","small"]' - echo 'go-tags=ent,enterprise' - echo 'is-enterprise=true' - echo 'vault-version-metadata=${{ inputs.vault-version }}+ent' - } | tee -a "$GITHUB_OUTPUT" + # Set CE, Ent, and CE in Ent specific workflow metadata + is_enterprise_repo='${{ contains(github.repository, 'vault-enterprise') }}' + if [ "$is_enterprise_repo" = 'true' ]; then + base_ref='${{ github.event.pull_request.base.ref || github.event.base_ref || github.ref_name || github.event.branch || github.ref }}' + is_ent_repo='true' + is_ce_in_enterprise=$([[ $base_ref == ce/* ]] && echo "true" || echo "false") + if [ "$is_ce_in_enterprise" = 'true' ]; then + is_enterprise="false" + go_tags='' + version_metadata='${{ inputs.vault-version }}' + else + is_enterprise='true' + go_tags='ent,enterprise' + version_metadata='${{ inputs.vault-version }}+ent' + fi + compute_build='["self-hosted","ondemand","os=linux","disk_gb=64","type=c6a.4xlarge"]' + compute_build_ui='["self-hosted","ondemand","os=linux", "disk_gb=64", "type=c6a.2xlarge"]' + compute_test_go='["self-hosted","ondemand","os=linux","disk_gb=64","type=c6a.2xlarge"]' + compute_test_ui='["self-hosted","ondemand","os=linux","type=m6a.2xlarge"]' + compute_small='["self-hosted","linux","small"]' else - { - echo 'compute-build="custom-linux-medium-vault-latest"' - echo 'compute-build-compat="custom-linux-medium-vault-latest"' - echo 'compute-build-ui="custom-linux-xl-vault-latest"' - echo 'compute-test-go="custom-linux-medium-vault-latest"' - echo 'compute-test-ui="custom-linux-medium-vault-latest"' - echo 'compute-small="ubuntu-latest"' - echo 'go-tags=' - echo 'is-enterprise=false' - echo 'vault-version-metadata=${{ inputs.vault-version }}' - } | tee -a "$GITHUB_OUTPUT" + compute_build='"custom-linux-medium-vault-latest"' + compute_build_ui='"custom-linux-xl-vault-latest"' + compute_test_go='"custom-linux-medium-vault-latest"' + compute_test_ui='"custom-linux-medium-vault-latest"' + compute_small='"ubuntu-latest"' + go_tags='' + is_ce_in_enterprise='false' + is_ent_branch='false' + is_ent_repo='false' + version_metadata='${{ inputs.vault-version }}' fi + { + echo "compute-build=${compute_build}" + echo "compute-build-ui=${compute_test_ui}" + echo "compute-test-go=${compute_test_go}" + echo "compute-test-ui=${compute_test_ui}" + echo "compute-small=${compute_small}" + echo "go-tags=${go_tags}" + echo "is-ce-in-enterprise=${is_ce_in_enterprise}" + echo "is-ent-branch=${is_enterprise}" + echo "is-ent-repo=${is_ent_repo}" + echo "vault-version-metadata=${version_metadata}" + } | tee -a "$GITHUB_OUTPUT" diff --git a/.github/actions/run-apupgrade-tests/action.yml b/.github/actions/run-apupgrade-tests/action.yml new file mode 100644 index 00000000000..2818739a66c --- /dev/null +++ b/.github/actions/run-apupgrade-tests/action.yml @@ -0,0 +1,120 @@ +# Copyright IBM Corp. 2016, 2025 +# SPDX-License-Identifier: BUSL-1.1 + +--- +name: Run Autopilot upgrade tests +description: | + This action runs the Autopilot upgrade tests on Vault Enterprise. + It downloads the needed Vault Enterprise source version binaries from the releases page, checks out the specified ref + from the Vault Enterprise repository, builds the target version binary of Vault for Autopilot upgrade testing, + and runs the Autopilot upgrade tool with the specified source versions. +inputs: + checkout-ref: + required: true + description: | + The branch, tag, or SHA to checkout from the Vault Enterprise repository, e.g. 'refs/heads/main'. + The target version binary of Vault for Autopilot upgrade testing will be built from this checkout. + github-token: + required: true + description: | + The GitHub token to use for checking out the needed repositories. + source-versions: + required: true + description: | + The source versions of Vault for Autopilot upgrade testing as a comma-separated string, + e.g. '1.16.9+ent,1.17.7+ent,1.18.0+ent'. + +runs: + using: composite + steps: + - name: Authenticate to Vault + id: vault-auth + shell: bash + run: vault-auth + - name: Fetch Secrets + id: secrets + uses: hashicorp/vault-action@4c06c5ccf5c0761b6029f56cfb1dcf5565918a3b # v3.4.0 + with: + url: ${{ steps.vault-auth.outputs.addr }} + caCertificate: ${{ steps.vault-auth.outputs.ca_certificate }} + token: ${{ steps.vault-auth.outputs.token }} + secrets: | + kv/data/github/${{ github.repository }}/github-token username-and-token | github-token; + kv/data/github/${{ github.repository }}/license license_1 | VAULT_LICENSE_CI; + kv/data/github/${{ github.repository }}/license license_2 | VAULT_LICENSE_2; + - name: Setup Git configuration (private) + id: setup-git-private + if: github.repository == 'hashicorp/vault-enterprise' + shell: bash + run: | + git config --global url."https://${{ steps.secrets.outputs.github-token }}@github.com".insteadOf https://github.com + - name: Check out the .release/versions.hcl file from Vault Enterprise repository + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + ref: ${{ inputs.checkout-ref }} + - uses: ./.github/actions/set-up-go + with: + github-token: ${{ inputs.github-token }} + - name: Build external tools + uses: ./.github/actions/install-tools + - name: Checkout VCM repository + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + repository: hashicorp/vcm + ref: 1fcab6591e3bdc81d2921ca77441bfcf913c6a57 + token: ${{ inputs.github-token }} + path: vcm + - name: Checkout Vault tools repository to get the Autopilot upgrade tool + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + repository: hashicorp/vault-tools + token: ${{ inputs.github-token }} + path: vault-tools + - name: Install needed Vault versions + env: + GOPATH: /home/runner/go + shell: bash + run: | + # Split the matched versions into an array + IFS=',' read -r -a versions <<< "${{ inputs.source-versions }}" + + for version in "${versions[@]}"; do + echo "Installing Vault version $version" + "${GITHUB_WORKSPACE}/vault-tools/vvm/vvm" install-ent "${version}" + done + - name: Build dev binary for binary tests + env: + GOPATH: /home/runner/go + GOPRIVATE: github.com/hashicorp/* + shell: bash + run: | + cd "${GITHUB_WORKSPACE}" || exit 1 + time make prep dev + + # Save the binary we just build under the current Vault version number to VVM + # for apupgrade to use as a target version + current_version=$(cat version/VERSION) + "${GITHUB_WORKSPACE}/vault-tools/vvm/vvm" save "${current_version}" + echo "VAULT_TARGET_VERSION=${current_version}" >> "${GITHUB_ENV}" + - name: Build VCM + shell: bash + run: | + cd "${GITHUB_WORKSPACE}/vcm" || exit 1 + make + - name: Build Autopilot upgrade tool + shell: bash + run: | + cd "${GITHUB_WORKSPACE}/vault-tools/apupgrade" || exit 1 + go build -o apupgrade . + - name: Run Autopilot upgrade tool + shell: bash + run: | + # Write the license to a file for VCM to use + echo "${{ steps.secrets.outputs.VAULT_LICENSE_CI }}" > "${GITHUB_WORKSPACE}/license.hclic" + export VAULT_LICENSE_PATH="${GITHUB_WORKSPACE}/license.hclic" + + # Unset VAULT_ADDR to avoid any conflicts with VCM and apupgrade + unset VAULT_ADDR + + echo "Running Autopilot upgrade tool with source versions: ${{ inputs.source-versions }} and target version: ${{ env.VAULT_TARGET_VERSION }}" + "${GITHUB_WORKSPACE}/vault-tools/apupgrade/apupgrade" -versions "${{ inputs.source-versions }},${VAULT_TARGET_VERSION}" -use-vvm diff --git a/.github/actions/set-up-buf/action.yml b/.github/actions/set-up-buf/action.yml deleted file mode 100644 index a9cd3656a10..00000000000 --- a/.github/actions/set-up-buf/action.yml +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: BUSL-1.1 - ---- -name: Set up buf from Github releases -description: Set up buf from Github releases - -inputs: - destination: - description: "Where to install the buf binary (default: $HOME/bin/buf)" - type: boolean - default: "$HOME/bin/buf" - version: - description: "The version to install (default: latest)" - type: string - default: Latest - -outputs: - destination: - description: Where the installed buf binary is - value: ${{ steps.install.outputs.destination }} - destination-dir: - description: The directory where the installed buf binary is - value: ${{ steps.install.outputs.destination-dir }} - version: - description: The installed version of buf - value: ${{ steps.install.outputs.version }} - -runs: - using: composite - steps: - - id: install - shell: bash - env: - GH_TOKEN: ${{ github.token }} - run: | - VERSION=$(gh release list -R bufbuild/buf --exclude-drafts --exclude-pre-releases | grep ${{ inputs.version }} | cut -f1) - - mkdir -p $(dirname ${{ inputs.destination }}) - DESTINATION="$(readlink -f "${{ inputs.destination }}")" - DESTINATION_DIR="$(dirname "$DESTINATION")" - echo "$DESTINATION_DIR" >> "$GITHUB_PATH" - - { - echo "destination=$DESTINATION" - echo "destination-dir=$DESTINATION_DIR" - echo "version=$VERSION" - } | tee -a "$GITHUB_OUTPUT" - - ARCH="$(echo "$RUNNER_ARCH" | tr '[:upper:]' '[:lower:]')" - OS="$RUNNER_OS" - if [ "$ARCH" = "x64" ]; then - export ARCH="x86_64" - fi - if [ "$ARCH" = "arm64" ] && [ "$OS" = "Linux" ]; then - export ARCH="aarch64" - fi - if [ "$OS" = "macOS" ]; then - export OS="Darwin" - fi - - mkdir -p tmp - gh release download "$VERSION" -p "buf-${OS}-${ARCH}.tar.gz" -O tmp/buf.tgz -R bufbuild/buf - pushd tmp && tar -xvf buf.tgz && popd - mv tmp/buf/bin/buf "$DESTINATION" - rm -rf tmp diff --git a/.github/actions/set-up-go/action.yml b/.github/actions/set-up-go/action.yml index 74a46f06f9d..881bf821a17 100644 --- a/.github/actions/set-up-go/action.yml +++ b/.github/actions/set-up-go/action.yml @@ -1,4 +1,4 @@ -# Copyright (c) HashiCorp, Inc. +# Copyright IBM Corp. 2016, 2025 # SPDX-License-Identifier: BUSL-1.1 --- @@ -8,14 +8,14 @@ description: Set up Go with a shared module cache. inputs: github-token: description: An elevated Github token to access private modules if necessary. - type: string no-restore: description: Whether or not to restore the Go module cache on a cache hit - type: boolean - default: false + default: "false" + no-save: + description: Whether or not to create a Go module cache on cache miss + default: "false" go-version: description: "Override .go-version" - type: string default: "" outputs: @@ -40,19 +40,30 @@ runs: else echo "go-version=${{ inputs.go-version }}" | tee -a "$GITHUB_OUTPUT" fi - - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version: ${{ steps.go-version.outputs.go-version }} cache: false # We use our own caching strategy - id: metadata shell: bash run: | + # Cache restore have some surprising relative pathing behavior we need + # to deal with. When actions/cache restores something it does it + # realtive to the check working directory. Since that can be different + # depending on our self-hosted vs Github hosted runners + # /home/runner/actions-runner/_work vs. /home/runner/work + # we need to factor in the absolute path of our working directory in our + # cache key. If we don't then cache restores will be incompatible on one + # or the other runner. + # + # See: https://github.com/actions/cache/issues/1127 + wd_hash=$(realpath . | sha256sum | head -c 8) { - echo "cache-path=$(go env GOMODCACHE)" - echo "cache-key=go-modules-${{ hashFiles('**/go.sum') }}" + echo "cache-path=$(go env GOMODCACHE)/cache" + echo "cache-key=go-modules-${wd_hash}-${{ hashFiles('**/go.sum') }}" } | tee -a "$GITHUB_OUTPUT" - id: cache-modules - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: enableCrossOsArchive: true lookup-only: ${{ inputs.no-restore }} @@ -71,7 +82,7 @@ runs: # keeps cache upload time, download time, and storage size to a minimum. path: ${{ steps.metadata.outputs.cache-path }} key: ${{ steps.metadata.outputs.cache-key }} - - if: steps.cache-modules.outputs.cache-hit != 'true' + - if: steps.cache-modules.outputs.cache-hit != 'true' && inputs.no-save != 'true' name: Download go modules shell: bash env: diff --git a/.github/actions/set-up-gofumpt/action.yml b/.github/actions/set-up-gofumpt/action.yml deleted file mode 100644 index d763656fc49..00000000000 --- a/.github/actions/set-up-gofumpt/action.yml +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: BUSL-1.1 - ---- -name: Set up gofumpt from Github releases -description: Set up gofumpt from Github releases - -inputs: - destination: - description: "Where to install the gofumpt binary (default: $HOME/bin/gofumpt)" - type: boolean - default: "$HOME/bin/gofumpt" - version: - description: "The version to install (default: latest)" - type: string - default: Latest - -outputs: - destination: - description: Where the installed gofumpt binary is - value: ${{ steps.install.outputs.destination }} - destination-dir: - description: The directory where the installed gofumpt binary is - value: ${{ steps.install.outputs.destination-dir }} - version: - description: The installed version of gofumpt - value: ${{ steps.install.outputs.version }} - -runs: - using: composite - steps: - - id: install - shell: bash - env: - GH_TOKEN: ${{ github.token }} - run: | - VERSION=$(gh release list -R mvdan/gofumpt --exclude-drafts --exclude-pre-releases | grep ${{ inputs.version }} | cut -f1) - - mkdir -p $(dirname ${{ inputs.destination }}) - DESTINATION="$(readlink -f "${{ inputs.destination }}")" - DESTINATION_DIR="$(dirname "$DESTINATION")" - echo "$DESTINATION_DIR" >> "$GITHUB_PATH" - - { - echo "destination=$DESTINATION" - echo "destination-dir=$DESTINATION_DIR" - echo "version=$VERSION" - } | tee -a "$GITHUB_OUTPUT" - - ARCH="$(echo "$RUNNER_ARCH" | tr '[:upper:]' '[:lower:]')" - OS="$(echo "$RUNNER_OS" | tr '[:upper:]' '[:lower:]')" - if [ "$ARCH" = "x64" ]; then - export ARCH="amd64" - fi - if [ "$OS" = "macos" ]; then - export OS="darwin" - fi - - gh release download "$VERSION" -p "gofumpt_*_${OS}_${ARCH}" -O gofumpt -R mvdan/gofumpt - chmod +x gofumpt - mv gofumpt "$DESTINATION" diff --git a/.github/actions/set-up-gosimports/action.yml b/.github/actions/set-up-gosimports/action.yml deleted file mode 100644 index 97602498b38..00000000000 --- a/.github/actions/set-up-gosimports/action.yml +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: BUSL-1.1 - ---- -name: Set up gosimports from Github releases -description: Set up gosimports from Github releases - -inputs: - destination: - description: "Where to install the gosimports binary (default: $HOME/bin/gosimports)" - type: boolean - default: "$HOME/bin/gosimports" - version: - description: "The version to install (default: latest)" - type: string - default: Latest - -outputs: - destination: - description: Where the installed gosimports binary is - value: ${{ steps.install.outputs.destination }} - destination-dir: - description: The directory where the installed gosimports binary is - value: ${{ steps.install.outputs.destination-dir }} - version: - description: The installed version of gosimports - value: ${{ steps.install.outputs.version }} - -runs: - using: composite - steps: - - id: install - shell: bash - env: - GH_TOKEN: ${{ github.token }} - run: | - VERSION=$(gh release list -R rinchsan/gosimports --exclude-drafts --exclude-pre-releases | grep ${{ inputs.version }} | cut -f1) - - mkdir -p $(dirname ${{ inputs.destination }}) - DESTINATION="$(readlink -f "${{ inputs.destination }}")" - DESTINATION_DIR="$(dirname "$DESTINATION")" - echo "$DESTINATION_DIR" >> "$GITHUB_PATH" - - { - echo "destination=$DESTINATION" - echo "version=$VERSION" - echo "destination-dir=$DESTINATION_DIR" - } | tee -a "$GITHUB_OUTPUT" - - ARCH="$(echo "$RUNNER_ARCH" | tr '[:upper:]' '[:lower:]')" - OS="$(echo "$RUNNER_OS" | tr '[:upper:]' '[:lower:]')" - if [ "$ARCH" = "x64" ]; then - export ARCH="amd64" - fi - if [ "$OS" = "macos" ]; then - export OS="darwin" - fi - - mkdir -p tmp - gh release download "$VERSION" -p "gosimports_*_${OS}_${ARCH}.tar.gz" -O tmp/gosimports.tgz -R rinchsan/gosimports - pushd tmp && tar -xvf gosimports.tgz && popd - mv tmp/gosimports "$DESTINATION" - rm -rf tmp diff --git a/.github/actions/set-up-gotestsum/action.yml b/.github/actions/set-up-gotestsum/action.yml deleted file mode 100644 index 9d0147313ae..00000000000 --- a/.github/actions/set-up-gotestsum/action.yml +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: BUSL-1.1 - ---- -name: Set up gotestsum from Github releases -description: Set up gotestsum from Github releases - -inputs: - destination: - description: "Where to install the gotestsum binary (default: $HOME/bin/gotestsum)" - type: boolean - default: "$HOME/bin/gotestsum" - version: - description: "The version to install (default: latest)" - type: string - default: Latest - -outputs: - destination: - description: Where the installed gotestsum binary is - value: ${{ steps.install.outputs.destination }} - destination-dir: - description: The directory where the installed gotestsum binary is - value: ${{ steps.install.outputs.destination-dir }} - version: - description: The installed version of gotestsum - value: ${{ steps.install.outputs.version }} - -runs: - using: composite - steps: - - id: install - shell: bash - env: - GH_TOKEN: ${{ github.token }} - run: | - VERSION=$(gh release list -R gotestyourself/gotestsum --exclude-drafts --exclude-pre-releases | grep ${{ inputs.version }} | cut -f1) - - mkdir -p $(dirname ${{ inputs.destination }}) - DESTINATION="$(readlink -f "${{ inputs.destination }}")" - DESTINATION_DIR="$(dirname "$DESTINATION")" - echo "$DESTINATION_DIR" >> "$GITHUB_PATH" - - { - echo "destination=$DESTINATION" - echo "destination-dir=$DESTINATION_DIR" - echo "version=$VERSION" - } | tee -a "$GITHUB_OUTPUT" - - OS="$(echo "$RUNNER_OS" | tr '[:upper:]' '[:lower:]')" - ARCH="$(echo "$RUNNER_ARCH" | tr '[:upper:]' '[:lower:]')" - if [ "$ARCH" = "x64" ]; then - export ARCH="amd64" - fi - - mkdir -p tmp - gh release download "$VERSION" -p "*${OS}_${ARCH}.tar.gz" -O tmp/gotestsum.tgz -R gotestyourself/gotestsum - pushd tmp && tar -xvf gotestsum.tgz && popd - mv tmp/gotestsum "$DESTINATION" - rm -rf tmp diff --git a/.github/actions/set-up-misspell/action.yml b/.github/actions/set-up-misspell/action.yml deleted file mode 100644 index 8f5d99fa5d0..00000000000 --- a/.github/actions/set-up-misspell/action.yml +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: BUSL-1.1 - ---- -name: Set up misspell from Github releases -description: Set up misspell from Github releases - -inputs: - destination: - description: "Where to install the misspell binary (default: $HOME/bin/misspell)" - type: boolean - default: "$HOME/bin/misspell" - version: - description: "The version to install (default: latest)" - type: string - default: Latest - -outputs: - destination: - description: Where the installed misspell binary is - value: ${{ steps.install.outputs.destination }} - destination-dir: - description: The directory where the installed misspell binary is - value: ${{ steps.install.outputs.destination-dir }} - version: - description: The installed version of misspell - value: ${{ steps.install.outputs.version }} - -runs: - using: composite - steps: - - id: install - shell: bash - env: - GH_TOKEN: ${{ github.token }} - run: | - VERSION=$(gh release list -R golangci/misspell --exclude-drafts --exclude-pre-releases | grep ${{ inputs.version }} | cut -f1) - - mkdir -p $(dirname ${{ inputs.destination }}) - DESTINATION="$(readlink -f "${{ inputs.destination }}")" - DESTINATION_DIR="$(dirname "$DESTINATION")" - echo "$DESTINATION_DIR" >> "$GITHUB_PATH" - - { - echo "destination=$DESTINATION" - echo "version=$VERSION" - echo "destination-dir=$DESTINATION_DIR" - } | tee -a "$GITHUB_OUTPUT" - - ARCH="$(echo "$RUNNER_ARCH" | tr '[:upper:]' '[:lower:]')" - OS="$(echo "$RUNNER_OS" | tr '[:upper:]' '[:lower:]')" - if [ "$ARCH" = "x64" ]; then - export ARCH="64bit" - fi - if [ "$OS" = "macos" ]; then - export OS="mac" - fi - - mkdir -p tmp - gh release download "$VERSION" -p "misspell_*_${OS}_${ARCH}.tar.gz" -O tmp/misspell.tgz -R golangci/misspell - pushd tmp && tar -xvf misspell.tgz && popd - mv tmp/misspell "$DESTINATION" - rm -rf tmp diff --git a/.github/actions/set-up-pipeline/action.yml b/.github/actions/set-up-pipeline/action.yml new file mode 100644 index 00000000000..1d1a3d95c4b --- /dev/null +++ b/.github/actions/set-up-pipeline/action.yml @@ -0,0 +1,48 @@ +# Copyright IBM Corp. 2016, 2025 +# SPDX-License-Identifier: BUSL-1.1 + +--- +name: Install the pipeline tool +description: Install the pipeline tool + +inputs: + github-token: + description: An elevated Github token to access private HashiCorp modules. + +runs: + using: composite + steps: + - uses: ./.github/actions/set-up-go + with: + github-token: ${{ inputs.github-token || github.token }} + no-restore: true # Don't download vault's modules for pipeline + no-save: true # Don't attempt to save modules either + - name: pipeline-metadata + id: pipeline-metadata + shell: bash + # Uses GITHUB_ENV instead of GITHUB_OUTPUT because composite actions are broken, + # see: https://github.com/actions/cache/issues/803#issuecomment-1793565071 + run: | + gobin=$(go env GOBIN) + if [[ -z "$gobin" ]]; then + gobin="$(go env GOPATH)/bin" + fi + { + echo "PIPELINE_HASH=$(git ls-tree HEAD tools/pipeline --object-only)" + echo "PIPELINE_PATH=$gobin/pipeline" + } | tee -a "$GITHUB_ENV" + - name: Try to restore pipeline from cache + id: pipeline-cache + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: ${{ env.PIPELINE_PATH }} + key: pipeline-${{ env.PIPELINE_HASH }} + - if: steps.pipeline-cache.outputs.cache-hit != 'true' + id: pipeline-build + name: Build pipeline + shell: bash + env: + GOPRIVATE: github.com/hashicorp/* + run: | + git config --global url."https://${{ inputs.github-token }}@github.com".insteadOf https://github.com + make tools-pipeline diff --git a/.github/actions/set-up-staticcheck/action.yml b/.github/actions/set-up-staticcheck/action.yml deleted file mode 100644 index cce079618fe..00000000000 --- a/.github/actions/set-up-staticcheck/action.yml +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: BUSL-1.1 - ---- -name: Set up staticcheck from Github releases -description: Set up staticcheck from Github releases - -inputs: - destination: - description: "Where to install the staticcheck binary (default: $HOME/bin/staticcheck)" - type: boolean - default: "$HOME/bin/staticcheck" - version: - description: "The version to install (default: latest)" - type: string - default: Latest - -outputs: - destination: - description: Where the installed staticcheck binary is - value: ${{ steps.install.outputs.destination }} - destination-dir: - description: The directory where the installed staticcheck binary is - value: ${{ steps.install.outputs.destination-dir }} - version: - description: The installed version of staticcheck - value: ${{ steps.install.outputs.version }} - -runs: - using: composite - steps: - - id: install - shell: bash - env: - GH_TOKEN: ${{ github.token }} - run: | - VERSION=$(gh release list -R dominikh/go-tools --exclude-drafts --exclude-pre-releases | grep ${{ inputs.version }} | cut -d " " -f2) - - mkdir -p $(dirname ${{ inputs.destination }}) - DESTINATION="$(readlink -f "${{ inputs.destination }}")" - DESTINATION_DIR="$(dirname "$DESTINATION")" - echo "$DESTINATION_DIR" >> "$GITHUB_PATH" - - { - echo "destination=$DESTINATION" - echo "destination-dir=$DESTINATION_DIR" - echo "version=$VERSION" - } | tee -a "$GITHUB_OUTPUT" - - ARCH="$(echo "$RUNNER_ARCH" | tr '[:upper:]' '[:lower:]')" - OS="$(echo "$RUNNER_OS" | tr '[:upper:]' '[:lower:]')" - if [ "$ARCH" = "x64" ]; then - export ARCH="amd64" - fi - if [ "$OS" = "macos" ]; then - export OS="darwin" - fi - - mkdir -p tmp - gh release download "$VERSION" -p "staticcheck_${OS}_${ARCH}.tar.gz" -O tmp/staticcheck.tgz -R dominikh/go-tools - pushd tmp && tar -xvf staticcheck.tgz && popd - mv tmp/staticcheck/staticcheck "$DESTINATION" - rm -rf tmp diff --git a/.github/docs/pull_request_template.md b/.github/docs/pull_request_template.md new file mode 100644 index 00000000000..6b9d11b9a10 --- /dev/null +++ b/.github/docs/pull_request_template.md @@ -0,0 +1,8 @@ +### Description +Why is this docs change needed? + +### TODO +- [ ] Preview the changes you made either locally or in the Vercel deployment + and make sure it looks correct. +- [ ] If you've added a new link to the sidebar navigation, make sure it's + sorted correctly. diff --git a/.github/instructions/generic/ember_general.instructions.md b/.github/instructions/generic/ember_general.instructions.md new file mode 100644 index 00000000000..d7b209f6385 --- /dev/null +++ b/.github/instructions/generic/ember_general.instructions.md @@ -0,0 +1,88 @@ +--- +applyTo: "vault/ui/**/*" +description: "HashiCorp Ember.js UI general guidelines - project context, build structure, and cross-cutting concerns" +--- + +# HashiCorp Ember.js UI General Guidelines + +This document provides general coding standards and project context for HashiCorp Ember.js UI applications. This serves as the central reference for project structure, framework information, and cross-cutting concerns. + +> **Related Documents**: See domain-specific guidelines in `ember_javascript.instructions.md`, `ember_hbs.instructions.md`, `ember_styles.instructions.md`, and `ember_tests.instructions.md`. + +## Project Context +HashiCorp Ember.js UI applications provide web-based interfaces for HashiCorp's infrastructure tools and cloud platforms. These applications serve enterprise-grade interfaces used by DevOps teams, platform engineers, security professionals, and system administrators to manage infrastructure, security policies, and operational workflows. + +Applications use modern Ember Octane patterns, Handlebars templates, and SCSS for styling with the HashiCorp Design System components. + +## Repository Structure +- `ui/app/components/` - Reusable UI components and their templates +- `ui/app/models/` - Ember Data models representing API entities +- `ui/app/routes/` - Route handlers for URL endpoints and data loading logic +- `ui/app/templates/` - Page-level Handlebars templates +- `ui/app/services/` - Ember services for shared functionality and state management +- `ui/app/helpers/` - Template helper functions for data formatting and logic +- `ui/tests/` - Integration, unit, and acceptance tests +- `ui/app/styles/` - SCSS stylesheets and component-specific styles +- `ui/config/` - Ember CLI configuration and environment settings +- `ui/mirage/` - Mock server configuration for development and testing + +## Framework and Tools +- **Frontend Framework**: Ember.js 4.x with Ember Octane patterns and decorators +- **Data Layer**: Ember Data for API communication with backend services +- **Templating**: Handlebars templates with Ember's component architecture +- **Styling**: SCSS with HashiCorp Design System (HDS) components and Bulma CSS framework +- **Build System**: Ember CLI with Webpack for bundling and asset management +- **Development**: ESLint for code linting, Prettier for code formatting + +## File Naming Conventions +- **Component Structure**: Components should have matching JavaScript/TypeScript and `.hbs` files in the same directory +- **Directory Organization**: Organize new components in logical subdirectories by feature or domain + +## Build and Deployment Structure +- **Development Build**: `ember serve` creates development server with live reload +- **Production Build**: `ember build --environment=production` generates optimized assets in `dist/` +- **Asset Output**: Built files are typically served by the application's backend server or embedded in the main binary +- **Integration**: UI is often compiled and integrated into the main application during release builds +- **Testing**: `ember test` runs the full test suite with QUnit in headless Chrome + +--- + +# Changelog Guidelines + +For files in the `changelog/` directory: +- **Enterprise features**: Use `ui (enterprise): descriptive text` +- **Community features**: Use `ui: descriptive text` +- Always indicate enterprise-only features in the description + +```javascript +// Changelog entries +"ui (enterprise): Add advanced policy filtering" // enterprise features +"ui: Fix configuration list pagination" // community features +``` + +--- + +# Dependency Management + +## package.json Guidelines +- Pin exact versions for critical dependencies or use tilde (`~`) for patch updates only +- **WARNING**: Avoid caret (`^`) operator which allows minor version updates that may introduce breaking changes +- Use tilde (`~`) for regular dependencies, exact versions for security-critical packages +- Dependencies in `resolutions` block MUST be pinned (no `~` or `^`) +- Keep `package.json` changes minimal and focused on the specific feature or fix +- Always commit lock files (`yarn.lock`, `package-lock.json`) with dependency changes +- Ensure package.json changes are independent of other code changes (except lock files) +- **Reminder**: Consider coordinating dependency changes with backend teams when the UI is embedded in application binaries + +Example dependency specification: +```json +{ + "dependencies": { + "lodash": "4.17.21", // exact version for critical packages + "express": "~4.18.0" // tilde for patch updates only + }, + "resolutions": { + "minimist": "1.2.6" // always exact for security fixes + } +} +``` diff --git a/.github/instructions/generic/ember_hbs.instructions.md b/.github/instructions/generic/ember_hbs.instructions.md new file mode 100644 index 00000000000..da67c4a51f5 --- /dev/null +++ b/.github/instructions/generic/ember_hbs.instructions.md @@ -0,0 +1,113 @@ +--- +applyTo: "vault/ui/**/*.hbs" +description: "HashiCorp Ember.js UI Handlebars template coding standards" +--- + +# HashiCorp Ember.js Handlebars Template Guidelines + +This document provides Handlebars template coding standards for HashiCorp Ember.js UI applications. + +> **Note**: For general project context, framework information, and repository structure, see `ember_general.instructions.md`. + +## Template Best Practices +- Check truthiness of arrays directly instead of using `.length` property +- Use string interpolation `"prefix/{{value}}"` instead of `{{concat}}` helper +- Remove unnecessary quotes around dynamic component arguments +- Use `Hds::Link::Inline` for external documentation links instead of `