diff --git a/.copywrite.hcl b/.copywrite.hcl index de6339ab4fd..de148843b44 100644 --- a/.copywrite.hcl +++ b/.copywrite.hcl @@ -10,7 +10,6 @@ project { header_ignore = [ "helper/pkcs7/**", "ui/node_modules/**", - "ui/api-client/**", "enos/modules/k8s_deploy_vault/raft-config.hcl", "plugins/database/postgresql/scram/**", ] diff --git a/.github/actionlint.yml b/.github/actionlint.yml index 60cb0777266..b707152ab48 100644 --- a/.github/actionlint.yml +++ b/.github/actionlint.yml @@ -6,6 +6,8 @@ self-hosted-runner: labels: - small - medium + - large + - xlarge - ondemand - disk_gb=64 - os=linux diff --git a/.github/actions/build-vault/action.yml b/.github/actions/build-vault/action.yml index af2057be373..7b9c36b3cbe 100644 --- a/.github/actions/build-vault/action.yml +++ b/.github/actions/build-vault/action.yml @@ -70,7 +70,7 @@ runs: 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@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 + uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 with: # Restore the UI asset from the UI build workflow. Never use a partial restore key. enableCrossOsArchive: true @@ -90,9 +90,11 @@ 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: @@ -110,7 +112,13 @@ runs: 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" + - 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: @@ -126,14 +134,38 @@ runs: shell: bash run: make ci-build - if: inputs.cgo-enabled == '1' - uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 + 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 - - if: inputs.cgo-enabled == '1' - name: Build CGO builder image + - 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 @@ -176,6 +208,8 @@ runs: - if: inputs.vault-edition != 'ce' shell: bash 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 @@ -198,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 diff --git a/.github/actions/checkout/action.yml b/.github/actions/checkout/action.yml index 7a3097a8311..b5a21c838b3 100644 --- a/.github/actions/checkout/action.yml +++ b/.github/actions/checkout/action.yml @@ -70,7 +70,7 @@ runs: echo "ref=${checkout_ref}" echo "depth=${fetch_depth}" } | tee -a "$GITHUB_OUTPUT" - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - 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 db164b3581e..64a17d01f55 100644 --- a/.github/actions/containerize/action.yml +++ b/.github/actions/containerize/action.yml @@ -38,6 +38,11 @@ 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: | @@ -48,6 +53,8 @@ runs: 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 }}' @@ -55,6 +62,8 @@ runs: docker_container_target='default' redhat_container_tags='quay.io/redhat-isv-containers/5f89bb9242e382c85087dce2:${{ inputs.vault-version }}-${{ inputs.vault-edition }}-ubi' redhat_container_target='ubi' + 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 }}' @@ -62,6 +71,8 @@ runs: 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 }}' @@ -69,6 +80,8 @@ runs: 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 @@ -81,6 +94,8 @@ runs: 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 @@ -93,6 +108,8 @@ runs: 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' @@ -104,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@v2.1.0 + 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@v2.1.0 + 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 index 5b7849ceed4..bb6e047145e 100644 --- a/.github/actions/create-dynamic-config/action.yml +++ b/.github/actions/create-dynamic-config/action.yml @@ -39,7 +39,7 @@ runs: } | tee -a "$GITHUB_ENV" - name: Try to restore dynamic config from cache id: dyn-cfg-cache - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 + uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 with: path: ${{ env.DYNAMIC_CONFIG_PATH }} key: dyn-cfg-${{ env.DYNAMIC_CONFIG_KEY }} diff --git a/.github/actions/metadata/action.yml b/.github/actions/metadata/action.yml index f19b4a9251d..b3aa319e849 100644 --- a/.github/actions/metadata/action.yml +++ b/.github/actions/metadata/action.yml @@ -39,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 }} @@ -102,9 +108,9 @@ runs: is_draft='${{ github.event.pull_request.draft }}' # Determine our pull request labels. We specifically look them up via the pulls API - # because at some point they stopped being reliable in the - # github.event.pull_request.labels.*.name context. - + # 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) @@ -145,28 +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-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-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 index 679bf0b9320..b482875c35c 100644 --- a/.github/actions/run-apupgrade-tests/action.yml +++ b/.github/actions/run-apupgrade-tests/action.yml @@ -36,7 +36,7 @@ runs: run: vault-auth - name: Fetch Secrets id: secrets - uses: hashicorp/vault-action@d1720f055e0635fd932a1d2a48f87a666a57906c # v3.0.0 + uses: hashicorp/vault-action@4c06c5ccf5c0761b6029f56cfb1dcf5565918a3b # v3.4.0 with: url: ${{ steps.vault-auth.outputs.addr }} caCertificate: ${{ steps.vault-auth.outputs.ca_certificate }} @@ -52,7 +52,7 @@ runs: 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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: ref: ${{ inputs.checkout-ref }} - uses: ./.github/actions/set-up-go @@ -61,14 +61,14 @@ runs: - name: Build external tools uses: ./.github/actions/install-external-tools - name: Checkout VCM repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + 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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: repository: hashicorp/vault-tools token: ${{ inputs.github-token }} diff --git a/.github/actions/set-up-go/action.yml b/.github/actions/set-up-go/action.yml index 702391ca960..7127f4e1ac8 100644 --- a/.github/actions/set-up-go/action.yml +++ b/.github/actions/set-up-go/action.yml @@ -40,7 +40,7 @@ runs: else echo "go-version=${{ inputs.go-version }}" | tee -a "$GITHUB_OUTPUT" fi - - uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.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 @@ -63,7 +63,7 @@ runs: echo "cache-key=go-modules-${wd_hash}-${{ hashFiles('**/go.sum') }}" } | tee -a "$GITHUB_OUTPUT" - id: cache-modules - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 + uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 with: enableCrossOsArchive: true lookup-only: ${{ inputs.no-restore }} diff --git a/.github/actions/set-up-gofumpt/action.yml b/.github/actions/set-up-gofumpt/action.yml index 5b5dd9bcb38..a05350e9ea6 100644 --- a/.github/actions/set-up-gofumpt/action.yml +++ b/.github/actions/set-up-gofumpt/action.yml @@ -11,9 +11,9 @@ inputs: type: boolean default: "$HOME/bin/gofumpt" version: - description: "The version to install (default: latest)" + description: "The version to install (default: v0.8.0)" type: string - default: "v0.7.0" + default: "v0.8.0" outputs: destination: diff --git a/.github/actions/set-up-gotestsum/action.yml b/.github/actions/set-up-gotestsum/action.yml index 391368a46af..15a99340c98 100644 --- a/.github/actions/set-up-gotestsum/action.yml +++ b/.github/actions/set-up-gotestsum/action.yml @@ -13,7 +13,7 @@ inputs: version: description: "The version to install (default: latest)" type: string - default: "v1.12.0" + default: "v1.12.3" outputs: destination: diff --git a/.github/actions/set-up-pipeline/action.yml b/.github/actions/set-up-pipeline/action.yml index 0145f375023..702802a93ab 100644 --- a/.github/actions/set-up-pipeline/action.yml +++ b/.github/actions/set-up-pipeline/action.yml @@ -33,7 +33,7 @@ runs: } | tee -a "$GITHUB_ENV" - name: Try to restore pipeline from cache id: pipeline-cache - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 + uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 with: path: ${{ env.PIPELINE_PATH }} key: pipeline-${{ env.PIPELINE_HASH }} 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 `