Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd3fc5cea7 |
No files matched your search
+2
-1
@@ -2,12 +2,13 @@ schema_version = 1
|
||||
|
||||
project {
|
||||
license = "BUSL-1.1"
|
||||
copyright_year = 2021
|
||||
copyright_year = 2024
|
||||
|
||||
# (OPTIONAL) A list of globs that should not have copyright/license headers.
|
||||
# Supports doublestar glob patterns for more flexibility in defining which
|
||||
# files or folders should be ignored
|
||||
header_ignore = [
|
||||
".github/**",
|
||||
".husky/**",
|
||||
"**/node_modules/**",
|
||||
"**/dist/**",
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
tags-ignore: ["**"]
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "41 5 * * *" # nightly: dependency audit + full test run
|
||||
|
||||
# One job on purpose: the shared runner pool is small, so everything runs
|
||||
# sequentially on a single runner instead of a matrix.
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 90
|
||||
env:
|
||||
CI: "true"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "22"
|
||||
|
||||
- name: install pnpm
|
||||
run: |
|
||||
npm install -g pnpm@10.33.3
|
||||
pnpm --version
|
||||
|
||||
- name: install dependencies
|
||||
# Lifecycle scripts are skipped: the desktop postinstall compiles
|
||||
# electron-app native modules, which the admin build and ember tests
|
||||
# do not need.
|
||||
run: pnpm install --frozen-lockfile --ignore-scripts
|
||||
|
||||
- name: install headless chrome
|
||||
# Debian/Ubuntu chromium from the distro archive (fast, mirrored),
|
||||
# exposed under the name testem's "Chrome" launcher looks for.
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if ! command -v google-chrome >/dev/null 2>&1; then
|
||||
SUDO=""; [ "$(id -u)" -ne 0 ] && SUDO="sudo"
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
$SUDO apt-get update -qq
|
||||
$SUDO apt-get install -y -qq --no-install-recommends chromium \
|
||||
|| $SUDO apt-get install -y -qq --no-install-recommends chromium-browser
|
||||
CHROME_BIN=$(command -v chromium || command -v chromium-browser)
|
||||
mkdir -p "$HOME/bin"
|
||||
ln -sf "$CHROME_BIN" "$HOME/bin/google-chrome"
|
||||
echo "$HOME/bin" >> "$GITHUB_PATH"
|
||||
fi
|
||||
PATH="$HOME/bin:$PATH" google-chrome --version
|
||||
|
||||
- name: build admin ui
|
||||
run: pnpm --filter admin build
|
||||
|
||||
- name: test addons
|
||||
run: |
|
||||
for a in core auth rose; do
|
||||
echo "::group::addons/$a"
|
||||
(cd addons/$a && npx ember test --test-port 0)
|
||||
echo "::endgroup::"
|
||||
done
|
||||
echo "::group::addons/api"
|
||||
(cd addons/api && npx ember exam --test-port 0 --split=4 --parallel=1)
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: test desktop ui
|
||||
run: cd ui/desktop && npx ember test --test-port 0
|
||||
|
||||
- name: test admin ui
|
||||
# The test build is made once and the partitions then run against the
|
||||
# static output, one browser at a time. Rebuilding in-process (and four
|
||||
# concurrent browsers) stalled on the small shared runners.
|
||||
run: |
|
||||
cd ui/admin
|
||||
npx ember build --environment=test --output-path="$RUNNER_TEMP/admin-test-dist"
|
||||
for p in 1 2 3 4; do
|
||||
echo "::group::admin partition $p/4"
|
||||
timeout 25m npx ember exam --test-port 0 --path "$RUNNER_TEMP/admin-test-dist" --split=4 --partition=$p
|
||||
echo "::endgroup::"
|
||||
done
|
||||
|
||||
- name: dependency audit
|
||||
# Fails on critical advisories only; remaining high/moderate advisories
|
||||
# are build/test tooling and are tracked in pnpm-overrides.md.
|
||||
run: |
|
||||
pnpm audit --audit-level=critical
|
||||
(cd ui/desktop/electron-app && pnpm audit --audit-level=critical)
|
||||
@@ -0,0 +1,2 @@
|
||||
# Anyone attached to this rule will always been assigned to a pull request
|
||||
* @hashicorp/boundary-ui
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Let us know about a bug!
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- Please reserve GitHub issues for bug reports and feature requests.
|
||||
|
||||
For questions, the best place to get answers is on our [discussion forum](https://discuss.hashicorp.com/c/boundary), as they will get more visibility from experienced users than the issue tracker.
|
||||
|
||||
Please note: We take Boundary's security and our users' trust very seriously. If you believe you have found a security issue in Boundary, please responsibly disclose this by contacting us at security@hashicorp.com. Our PGP key is available on [our security page](https://www.hashicorp.com/security/).
|
||||
|
||||
Logging is available on Boundary Desktop Client version >= 2.1.0
|
||||
|
||||
Logs are found at:
|
||||
|
||||
Linux: ~/.config/Boundary/logs/desktop-client.log
|
||||
MacOS: ~/Library/Logs/Boundary/desktop-client.log
|
||||
Windows: $env:USERPROFILE\AppData\Roaming\Boundary\logs\desktop-client.log
|
||||
|
||||
If requests are taking longer than expected, please change the logging level to DEBUG. This will log the cache daemon request times as well.
|
||||
|
||||
-->
|
||||
|
||||
## :bug: Bug Report
|
||||
|
||||
### **Description**
|
||||
|
||||
_A clear and concise description of the bug._
|
||||
|
||||
### **Steps to Reproduce**
|
||||
|
||||
1. Go to '...'
|
||||
2. Click on '...'
|
||||
3. Scroll down to '...'
|
||||
4. See the error
|
||||
|
||||
## **Expected behavior**
|
||||
|
||||
_A clear description of what you expected to happen._
|
||||
|
||||
## **Actual behavior**
|
||||
|
||||
_A clear description of what actually happened._
|
||||
|
||||
## **Screenshots (if applicable)**
|
||||
|
||||
_Add screenshots or screen recordings to help explain the issue._
|
||||
|
||||
## **Environment**
|
||||
|
||||
- **OS and Version:** (e.g., Windows 10 (22H2), macOS (14.7.2))
|
||||
- **Architecture:** (e.g., arm64, x86_64)
|
||||
- **Browser/Version:** (if applicable)
|
||||
- **Desktop Client Version:** (if applicable)
|
||||
- **Controller/worker versions:** (if applicable)
|
||||
|
||||
## **Logs & Console Output (if applicable)**
|
||||
|
||||
_Paste any relevant error logs or browser console output here._
|
||||
|
||||
## **Additional Context**
|
||||
|
||||
_Any other details that might be relevant._
|
||||
@@ -0,0 +1,7 @@
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
contact_links:
|
||||
- name: Ask a question
|
||||
url: https://discuss.hashicorp.com/c/boundary
|
||||
about: For increased visibility, please post questions on the discussion forum.
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest something!
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Explain any additional use-cases**
|
||||
If there are any use-cases that would help us understand the use/need/value please share them as they can help us decide on acceptance and prioritization.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -0,0 +1,6 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
@@ -0,0 +1,30 @@
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
addons:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: "addons/**/*"
|
||||
|
||||
api-addon:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: "addons/api/**/*"
|
||||
|
||||
auth-addon:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: "addons/auth/**/*"
|
||||
|
||||
styles-addon:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: "addons/rose/**/*"
|
||||
|
||||
ui:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: "ui/**/*"
|
||||
|
||||
admin:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: "ui/admin/**/*"
|
||||
|
||||
desktop:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: "ui/desktop/**/*"
|
||||
@@ -0,0 +1,33 @@
|
||||
# Description
|
||||
<!-- Add a brief description of changes here -->
|
||||
|
||||
<!-- Uncomment line below to manually add link to JIRA ticket -->
|
||||
<!-- :tickets: [Jira ticket](https://hashicorp.atlassian.net/browse/JIRA_TICKET_NUMBER) -->
|
||||
|
||||
## Screenshots (if appropriate)
|
||||
|
||||
## How to Test
|
||||
<!-- Add steps to test this change. Include any other necessary relevant links -->
|
||||
|
||||
## Checklist
|
||||
<!-- strikethrough the checklist item that is not relevant to your change -->
|
||||
|
||||
<!-- If you are merging a long lived branch, major feature, or UI altering changes,
|
||||
please add the a11y-tests label. Other cases, like a dependency change or
|
||||
translation update likely does not need an a11y audit -->
|
||||
|
||||
- [ ] I have added before and after screenshots for UI changes
|
||||
- [ ] I have added JSON response output for API changes
|
||||
- [ ] I have added steps to reproduce and test for bug fixes in the description
|
||||
- [ ] I have commented on my code, particularly in hard-to-understand areas
|
||||
- [ ] My changes generate no new warnings
|
||||
- [ ] I have added tests that prove my fix is effective or that my feature works
|
||||
- [ ] I have added `a11y-tests` label to run a11y audit tests if needed
|
||||
|
||||
## PCI review checklist
|
||||
|
||||
<!-- heimdall_github_prtemplate:grc-pci_dss-2024-01-05 -->
|
||||
- [ ] I have documented a clear reason for, and description of, the change I am making.
|
||||
- [ ] If applicable, I've documented a plan to revert these changes if they require more than reverting the pull request.
|
||||
- [ ] If applicable, I've documented the impact of any changes to security controls.
|
||||
Examples of changes to security controls include using new access control methods, adding or removing logging pipelines, etc.
|
||||
Executable
+94
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Configure Git
|
||||
git config --global user.email "hc-github-team-secure-boundary@hashicorp.com"
|
||||
git config --global user.name "github-team-secure-boundary"
|
||||
# Fetch branches from ENT
|
||||
git fetch origin
|
||||
BRANCH=${1}
|
||||
|
||||
echo "BRANCH to merge is $BRANCH"
|
||||
git checkout "${BRANCH}"
|
||||
|
||||
# Checkout OSS repo
|
||||
git remote add oss-remote https://github.com/hashicorp/boundary-ui.git
|
||||
git fetch oss-remote
|
||||
|
||||
# Merge oss/${BRANCH} into ent/${BRANCH}
|
||||
git_merge_branch="${2}"
|
||||
git checkout -b "${git_merge_branch}"
|
||||
latest_oss_commit="$(git rev-parse --short oss-remote/${BRANCH})"
|
||||
echo "Trying to merge the latest oss commit - ${latest_oss_commit} from oss/${BRANCH} into ent/${BRANCH}"
|
||||
|
||||
if ! errors=$(git merge -m "Merge Boundary UI OSS branch '${BRANCH}' at commit ${latest_oss_commit}" "${latest_oss_commit}"); then
|
||||
# Here we can try to auto resolve conflicts
|
||||
# This logic will vary from project to project. The below is just an example.
|
||||
conflicts=$(git diff --name-only --diff-filter=U)
|
||||
printf "Found conflicts:\n${conflicts}\n"
|
||||
# Resolve package.json conflicts by taking oss
|
||||
if echo "$conflicts" | grep -q package.json; then
|
||||
echo "Checking out oss package.json..."
|
||||
git checkout --theirs package.json
|
||||
git add package.json
|
||||
fi
|
||||
# Resolve pnpm-lock.yaml conflicts by re-running pnpm install:
|
||||
# https://pnpm.io/git#merge-conflicts
|
||||
if echo "$conflicts" | grep -q pnpm-lock.yaml; then
|
||||
echo "Re-running pnpm install to fix conflicts by regenerating pnpm-lock.yaml..."
|
||||
pnpm install
|
||||
git add pnpm-lock.yaml
|
||||
fi
|
||||
|
||||
# If we can commit all the changes without conflict, we have resolved everything automatically
|
||||
if ! git commit --no-edit; then
|
||||
echo "Auto Merge failed, creating a draft PR"
|
||||
git merge --abort
|
||||
git clean -xfd
|
||||
git fetch oss-remote
|
||||
git checkout "${OSS_BRANCH}"
|
||||
git checkout -b "${OSS_LOCAL_BRANCH}"
|
||||
git push -f --set-upstream origin "${OSS_LOCAL_BRANCH}"
|
||||
gh pr create \
|
||||
--draft \
|
||||
--fill-first \
|
||||
--label "oss-merge" \
|
||||
-B "${BASE_BRANCH}" \
|
||||
-H "${OSS_LOCAL_BRANCH}" \
|
||||
-a "${ACTOR}" \
|
||||
-t "[${BASE_BRANCH/oss\/release\//}] OSS to ENT merge of (${SHA::7})" \
|
||||
-b "${BASE_BRANCH/oss\//} upstream merge of (${SHA::7})
|
||||
Merge failed, Please fix the conflicts using github UI or using the following commands:
|
||||
\`\`\`bash
|
||||
git checkout ${BASE_BRANCH}
|
||||
git pull
|
||||
git checkout ${OSS_LOCAL_BRANCH}
|
||||
git merge ${BASE_BRANCH}
|
||||
# fix conflicts and commit
|
||||
git push origin ${OSS_LOCAL_BRANCH}
|
||||
\`\`\`"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check that there are actually changes to merge by comparing the
|
||||
# merge branch to the current checked out branch
|
||||
if (git diff ${BRANCH} --exit-code > /dev/null); then
|
||||
echo "there are no changes to merge"
|
||||
exit 0
|
||||
fi
|
||||
git push origin "${git_merge_branch}"
|
||||
gh pr create \
|
||||
--fill-first \
|
||||
--label "oss-merge" \
|
||||
-B "${BASE_BRANCH}" \
|
||||
-H "${MERGE_BRANCH}" \
|
||||
-a ${ACTOR} \
|
||||
-t "[${BASE_BRANCH/oss\/release\//}] OSS to ENT merge of (${SHA::7})" \
|
||||
-b "${BASE_BRANCH/oss\//} upstream merge of (${SHA::7})"
|
||||
gh pr merge --auto --merge
|
||||
|
||||
# This PR will be need to be approved manually
|
||||
@@ -0,0 +1,56 @@
|
||||
name: A11y Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [labeled, opened, synchronize, reopened]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
||||
a11y-test:
|
||||
name: Run A11y Tests
|
||||
if: contains(github.event.pull_request.labels.*.name, 'a11y-tests')
|
||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||
timeout-minutes: 40
|
||||
steps:
|
||||
- uses: browser-actions/setup-chrome@b94431e051d1c52dcbe9a7092a4f10f827795416 # v2.1.0
|
||||
with:
|
||||
install-dependencies: true
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||
with:
|
||||
run_install: false
|
||||
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: '**/pnpm-lock.yaml'
|
||||
- run: pnpm install
|
||||
- name: Run a11y tests
|
||||
env:
|
||||
# this will generate the test reports but causes tests to pass even when there a11y failures
|
||||
ENABLE_A11Y_MIDDLEWARE_REPORTER: true
|
||||
run: pnpm test-a11y
|
||||
- name: Consolidate ember a11y reports
|
||||
run: |
|
||||
mkdir ember-a11y-reports
|
||||
jq -s 'map(.[])' ./ui/admin/ember-a11y-report/*.json > ember-a11y-reports/admin.json
|
||||
jq -s 'map(.[])' ./ui/desktop/ember-a11y-report/*.json > ember-a11y-reports/desktop.json
|
||||
- name: Output ember a11y test report summary (admin)
|
||||
run: 'cat ember-a11y-reports/admin.json | jq "map({moduleName,testName,routes,urls,violations: .violations | map({id, nodes: .nodes | map({failureSummary, targets: .[].[]?.relatedNodes?.[]?.target? })}) })"'
|
||||
- name: Output ember a11y test report summary (desktop)
|
||||
run: 'cat ember-a11y-reports/desktop.json | jq "map({moduleName,testName,routes,urls,violations: .violations | map({id, nodes: .nodes | map({failureSummary, targets: .[].[]?.relatedNodes?.[]?.target? })}) })"'
|
||||
- name: Upload ember a11y reports
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
with:
|
||||
name: ember-a11y-reports
|
||||
path: ./ember-a11y-reports
|
||||
- name: Report a11y test results status
|
||||
if: always()
|
||||
# fail CI when the combined array length of admin and desktop a11y reports is not 0
|
||||
run: |
|
||||
EMBER_A11Y_FAILURE_COUNT=$(jq -s 'map(.[]) | length' ember-a11y-reports/admin.json ember-a11y-reports/desktop.json)
|
||||
echo "$EMBER_A11Y_FAILURE_COUNT ember-a11y test failures"
|
||||
if [ "$EMBER_A11Y_FAILURE_COUNT" != '0' ]; then
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,94 @@
|
||||
name: Build Admin UI
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- "release/**"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
dependencies:
|
||||
name: Install dependencies
|
||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||
with:
|
||||
run_install: false
|
||||
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: '**/pnpm-lock.yaml'
|
||||
- run: pnpm install --frozen-lockfile
|
||||
build-admin-ui-oss:
|
||||
name: Build Admin UI OSS
|
||||
needs: [dependencies]
|
||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||
with:
|
||||
run_install: false
|
||||
- name: Build
|
||||
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: '**/pnpm-lock.yaml'
|
||||
- run: pnpm install --offline
|
||||
- run: pnpm run build:ui:admin:oss
|
||||
- name: Upload artifact admin-ui
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
with:
|
||||
name: admin-ui
|
||||
path: ./ui/admin/dist/
|
||||
- name: Upload artifact OSS admin UI
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
with:
|
||||
name: admin-ui-oss
|
||||
path: ./ui/admin/dist/
|
||||
build-admin-ui-enterprise:
|
||||
name: Build Admin UI Enterprise
|
||||
needs: [dependencies]
|
||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||
with:
|
||||
run_install: false
|
||||
- name: Build
|
||||
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: '**/pnpm-lock.yaml'
|
||||
- run: pnpm install --offline
|
||||
- run: pnpm run build:ui:admin:enterprise
|
||||
- name: Upload artifact enterprise admin UI
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
with:
|
||||
name: admin-ui-ent
|
||||
path: ./ui/admin/dist/
|
||||
build-admin-ui-hcp:
|
||||
name: Build Admin UI HCP
|
||||
needs: [dependencies]
|
||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||
with:
|
||||
run_install: false
|
||||
- name: Build
|
||||
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: '**/pnpm-lock.yaml'
|
||||
- run: pnpm install --offline
|
||||
- run: pnpm run build:ui:admin:hcp
|
||||
- name: Upload artifact HCP admin UI
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
with:
|
||||
name: admin-ui-hcp
|
||||
path: ./ui/admin/dist/
|
||||
@@ -0,0 +1,57 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [main]
|
||||
schedule:
|
||||
- cron: '0 19 * * 4'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Override automatic language detection by changing the below list
|
||||
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
|
||||
language: ['javascript']
|
||||
# Learn more...
|
||||
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@70df9def86d22bf0ea4e7f8b956e7b92e7c1ea22 # codeql-bundle-v2.20.7
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@70df9def86d22bf0ea4e7f8b956e7b92e7c1ea22 # codeql-bundle-v2.20.7
|
||||
@@ -0,0 +1,19 @@
|
||||
name: Add Copyright Headers
|
||||
on: pull_request
|
||||
jobs:
|
||||
copywrite:
|
||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
# Ref and repository aren't normally needed, this is a workaround for a bug in auto commit
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
- uses: hashicorp/setup-copywrite@32638da2d4e81d56a0764aa1547882fc4d209636 # v1.1.3
|
||||
- name: Add missing Copyright Headers
|
||||
run: copywrite headers
|
||||
- uses: stefanzweifel/git-auto-commit-action@28e16e81777b558cc906c8750092100bbb34c5e3 # v7.0.0
|
||||
with:
|
||||
commit_message: Add missing copyright headers
|
||||
@@ -0,0 +1,107 @@
|
||||
on:
|
||||
issues:
|
||||
types: [opened, closed, deleted, reopened]
|
||||
pull_request_target:
|
||||
types: [opened, closed, reopened]
|
||||
issue_comment: # Also triggers when commenting on a PR from the conversation view
|
||||
types: [created]
|
||||
workflow_dispatch:
|
||||
|
||||
name: Jira Sync
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||
name: Jira sync
|
||||
steps:
|
||||
- name: Check if community user
|
||||
if: github.event.action == 'opened'
|
||||
id: boundary-team-role
|
||||
run: |
|
||||
TEAM=boundary
|
||||
ROLE="$(gh api orgs/hashicorp/teams/${TEAM}/memberships/${{ github.actor }} | jq -r '.role | select(.!=null)')"
|
||||
if [[ -n ${ROLE} ]]; then
|
||||
echo "Actor ${{ github.actor }} is a ${TEAM} team member, skipping ticket creation"
|
||||
else
|
||||
echo "Actor ${{ github.actor }} is not a ${TEAM} team member"
|
||||
fi
|
||||
echo "role=${ROLE}" >> $GITHUB_OUTPUT
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.JIRA_SYNC_GITHUB_TOKEN }}
|
||||
|
||||
- name: Set ticket type
|
||||
if: github.event.action == 'opened' && !steps.boundary-team-role.outputs.role
|
||||
id: set-ticket-type
|
||||
run: |
|
||||
if [[ "${{ github.event_name }}" == "pull_request_target" ]]; then
|
||||
echo "type=PR" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "type=ISS" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Create ticket
|
||||
if: github.event.action == 'opened' && !steps.boundary-team-role.outputs.role
|
||||
uses: tomhjp/gh-action-jira-create@3ed1789cad3521292e591a7cfa703215ec1348bf # v0.2.1
|
||||
env:
|
||||
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
|
||||
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
|
||||
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
|
||||
with:
|
||||
project: ICU
|
||||
issuetype: "GH Issue"
|
||||
summary: "${{ github.event.repository.name }} [${{ steps.set-ticket-type.outputs.type }} #${{ github.event.issue.number || github.event.pull_request.number }}]: ${{ github.event.issue.title || github.event.pull_request.title }}"
|
||||
description: "${{ github.event.issue.body || github.event.pull_request.body }}\n\n_Created from GitHub Action for ${{ github.event.issue.html_url || github.event.pull_request.html_url }}, from ${{ github.actor }}_"
|
||||
# customfield_10089 is Issue Link custom field
|
||||
# customfield_10091 is team custom field
|
||||
extraFields: '{"customfield_10089": "${{ github.event.issue.html_url || github.event.pull_request.html_url }}"}'
|
||||
|
||||
- name: Search
|
||||
if: github.event.action != 'opened'
|
||||
id: search
|
||||
uses: tomhjp/gh-action-jira-search@04700b457f317c3e341ce90da5a3ff4ce058f2fa # v0.2.2
|
||||
env:
|
||||
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
|
||||
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
|
||||
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
|
||||
with:
|
||||
# cf[10089] is Issue Link custom field
|
||||
jql: 'issuetype = "GH Issue" and cf[10089]="${{ github.event.issue.html_url || github.event.pull_request.html_url }}"'
|
||||
|
||||
- name: Sync comment
|
||||
if: github.event.action == 'created' && steps.search.outputs.issue
|
||||
uses: tomhjp/gh-action-jira-comment@6eb6b9ead70221916b6badd118c24535ed220bd9 # v0.2.0
|
||||
env:
|
||||
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
|
||||
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
|
||||
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
|
||||
with:
|
||||
issue: ${{ steps.search.outputs.issue }}
|
||||
comment: "${{ github.actor }} ${{ github.event.review.state || 'commented' }}:\n\n${{ github.event.comment.body || github.event.review.body }}\n\n${{ github.event.comment.html_url || github.event.review.html_url }}"
|
||||
|
||||
- name: Transitions
|
||||
id: transitions
|
||||
if: steps.search.outputs.issue
|
||||
run: |
|
||||
if [[ "${{ github.event.action }}" == "closed" || "${{ github.event.action }}" == "deleted" ]]; then
|
||||
echo "Closing ticket"
|
||||
echo "name=Done" >> "$GITHUB_OUTPUT"
|
||||
elif [[ "${{ github.event.action }}" == "reopened" ]]; then
|
||||
echo "Reopening ticket"
|
||||
echo "name=Reopen" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
# Transition issue API reference: https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-issueidorkey-transitions-post
|
||||
- name: Transition ticket
|
||||
if: steps.transitions.outputs.name
|
||||
run: |
|
||||
transitions="$(curl --silent \
|
||||
--url "${{ secrets.JIRA_BASE_URL }}rest/api/3/issue/${{ steps.search.outputs.issue }}/transitions" \
|
||||
--user "${{ secrets.JIRA_USER_EMAIL }}:${{ secrets.JIRA_API_TOKEN }}" \
|
||||
--header "Accept: application/json")"
|
||||
id="$(echo "${transitions}" | jq -r '.transitions[] | select(.name == "${{ steps.transitions.outputs.name }}") | .id')"
|
||||
curl --silent \
|
||||
--url "${{ secrets.JIRA_BASE_URL }}rest/api/3/issue/${{ steps.search.outputs.issue }}/transitions" \
|
||||
--user "${{ secrets.JIRA_USER_EMAIL }}:${{ secrets.JIRA_API_TOKEN }}" \
|
||||
--header "Accept: application/json" \
|
||||
--header "Content-Type: application/json" \
|
||||
--data "$(printf '{"transition": {"id": "%s"}}' "${id}")"
|
||||
@@ -0,0 +1,11 @@
|
||||
name: "Pull Request Labeler"
|
||||
on:
|
||||
- pull_request_target
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||
steps:
|
||||
- uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
@@ -0,0 +1,74 @@
|
||||
name: Validate Monorepo
|
||||
on: pull_request
|
||||
jobs:
|
||||
|
||||
dependencies:
|
||||
name: Install dependencies
|
||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||
with:
|
||||
run_install: false
|
||||
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: '**/pnpm-lock.yaml'
|
||||
- run: pnpm install --frozen-lockfile
|
||||
|
||||
compliance:
|
||||
name: License Compliance
|
||||
needs: [dependencies]
|
||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||
with:
|
||||
run_install: false
|
||||
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: '**/pnpm-lock.yaml'
|
||||
- run: pnpm install --offline
|
||||
- run: pnpm run compliance:licenses
|
||||
|
||||
lint:
|
||||
name: Lint
|
||||
needs: [dependencies, compliance]
|
||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||
with:
|
||||
run_install: false
|
||||
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: '**/pnpm-lock.yaml'
|
||||
- run: pnpm install --offline
|
||||
- run: pnpm lint
|
||||
|
||||
test:
|
||||
name: Test
|
||||
needs: [lint]
|
||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: browser-actions/setup-chrome@b94431e051d1c52dcbe9a7092a4f10f827795416 # v2.1.0
|
||||
with:
|
||||
install-dependencies: true
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||
with:
|
||||
run_install: false
|
||||
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: '**/pnpm-lock.yaml'
|
||||
- run: pnpm install --offline
|
||||
- run: pnpm test
|
||||
@@ -0,0 +1,25 @@
|
||||
name: Trigger OSS to Enterprise Merge
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- closed
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
trigger-oss-merge:
|
||||
# Run this only on merge events in OSS repo
|
||||
if: ${{ github.event.pull_request.merged && github.repository == 'hashicorp/boundary-ui' }}
|
||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||
steps:
|
||||
- name: Trigger Merge
|
||||
env:
|
||||
GIT_REF: ${{ github.ref_name }}
|
||||
GIT_SHA: ${{ github.sha }}
|
||||
GH_PAT: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
|
||||
GIT_ACTOR: ${{ github.actor }}
|
||||
run: |
|
||||
curl -H "Authorization: token $GH_PAT" \
|
||||
-H 'Accept: application/json' \
|
||||
-d "{\"event_type\": \"oss-merge\", \"client_payload\": {\"git-ref\": \"${GIT_REF}\", \"git-sha\": \"${GIT_SHA}\", \"git-actor\": \"${GIT_ACTOR}\" }}" \
|
||||
"https://api.github.com/repos/hashicorp/boundary-ui-enterprise/dispatches"
|
||||
@@ -0,0 +1,24 @@
|
||||
name: OSS → ENT Merge
|
||||
on:
|
||||
repository_dispatch:
|
||||
types: [ oss-merge ]
|
||||
jobs:
|
||||
oss-merge:
|
||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
token: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
|
||||
- run: |
|
||||
git fetch --prune --unshallow
|
||||
./.github/scripts/merge.sh "${BASE_BRANCH}" "${MERGE_BRANCH}"
|
||||
env:
|
||||
BASE_BRANCH: ${{ github.event.client_payload.git-ref }}
|
||||
OSS_BRANCH: oss-remote/${{ github.event.client_payload.git-ref }}
|
||||
OSS_LOCAL_BRANCH: oss/${{ github.event.client_payload.git-ref }}-${{ github.event.client_payload.git-sha }}
|
||||
MERGE_BRANCH: oss/merge-${{ github.event.client_payload.git-ref }}-${{github.event.client_payload.git-sha}}
|
||||
GITHUB_TOKEN: ${{secrets.ELEVATED_GITHUB_TOKEN }}
|
||||
MERGE_APPROVE_TOKEN: ${{secrets.ELEVATED_GITHUB_TOKEN }}
|
||||
ACTOR: ${{ github.event.client_payload.git-actor }}
|
||||
SHA: ${{github.event.client_payload.git-sha}}
|
||||
@@ -0,0 +1,207 @@
|
||||
name: Test E2E Admin UI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [labeled, opened, synchronize, reopened]
|
||||
paths:
|
||||
- 'ui/admin/**'
|
||||
- 'e2e-tests/*'
|
||||
- 'e2e-tests/api-client/**'
|
||||
- 'e2e-tests/helpers/**'
|
||||
- 'e2e-tests/admin/**'
|
||||
- '.github/workflows/test-e2e-admin-ui.yaml'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
boundary-enterprise-branch:
|
||||
description: 'Branch of boundary-enterprise to test against (default to main)'
|
||||
required: true
|
||||
default: 'main'
|
||||
type: string
|
||||
boundary-branch:
|
||||
description: 'Branch of boundary to test against (default to main)'
|
||||
required: true
|
||||
default: 'main'
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: test
|
||||
runs-on: ${{ fromJSON(vars.RUNNER_UBUNTU_22) }}
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- boundary_edition: community
|
||||
github_repo: hashicorp/boundary
|
||||
folder_name: boundary
|
||||
boundary_edition_short: oss
|
||||
enos_scenario: e2e_ui_docker
|
||||
test_command: admin:ce:docker
|
||||
boundary_branch: ${{ github.event.inputs.boundary-branch || 'main' }}
|
||||
- boundary_edition: enterprise
|
||||
github_repo: hashicorp/boundary-enterprise
|
||||
folder_name: boundary-enterprise
|
||||
boundary_edition_short: ent
|
||||
enos_scenario: e2e_ui_docker_ent
|
||||
test_command: admin:ent:docker
|
||||
boundary_branch: ${{ github.event.inputs.boundary-enterprise-branch || 'main' }}
|
||||
fail-fast: false
|
||||
env:
|
||||
ENOS_VAR_e2e_debug_no_run: true
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up pnpm
|
||||
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||
with:
|
||||
run_install: false
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "pnpm"
|
||||
cache-dependency-path: |
|
||||
pnpm-lock.yaml
|
||||
ui/desktop/electron-app/pnpm-lock.yaml
|
||||
|
||||
- name: Set up Terraform
|
||||
uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd
|
||||
|
||||
- name: Set up Enos
|
||||
uses: hashicorp/action-setup-enos@39a8f388434bea5eeba6649b99aa9949a55a1150
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Install Vault CLI
|
||||
run: |
|
||||
wget https://releases.hashicorp.com/vault/1.12.2/vault_1.12.2_linux_amd64.zip -O /tmp/vault.zip
|
||||
unzip /tmp/vault.zip -d /usr/local/bin
|
||||
|
||||
- name: GPG setup
|
||||
run: |
|
||||
# Create a GPG key
|
||||
export KEY_PW=boundary
|
||||
gpg --generate-key --batch <<eoGpgConf
|
||||
%echo Started!
|
||||
Key-Type: RSA
|
||||
Key-Length: default
|
||||
Subkey-Type: RSA
|
||||
Name-Real: boundary
|
||||
Name-Comment: default
|
||||
Name-Email: default
|
||||
Expire-Date: 0
|
||||
Passphrase: $KEY_PW
|
||||
%commit
|
||||
%echo Done.
|
||||
eoGpgConf
|
||||
|
||||
# Enable gpg-preset-passphrase so that key passwords can be saved
|
||||
echo "allow-preset-passphrase" >> ~/.gnupg/gpg-agent.conf
|
||||
gpg-connect-agent reloadagent /bye &>/dev/null
|
||||
|
||||
# Get information about the created keys
|
||||
export lines=$(gpg --list-secret-keys --with-colons --with-keygrip)
|
||||
export KEY_ID=""
|
||||
while read -r line
|
||||
do
|
||||
# Save the first key id to be used later
|
||||
if [[ $line =~ "fpr"* ]]; then
|
||||
if [[ $KEY_ID == "" ]]; then
|
||||
KEY_ID="$(echo "$line" | sed -r 's/fpr|://g')"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Cache the passphrases for the keys so passwords do not need to be entered
|
||||
if [[ $line =~ "grp"* ]]; then
|
||||
export KEYGRIP_ID="$(echo "$line" | sed -r 's/grp|://g')"
|
||||
/usr/lib/gnupg/gpg-preset-passphrase --preset -P $KEY_PW $KEYGRIP_ID
|
||||
fi
|
||||
done <<< $lines
|
||||
|
||||
# Trust the key
|
||||
touch /tmp/test.txt
|
||||
gpg -a --encrypt -r $KEY_ID --trust-model always --batch --yes /tmp/test.txt
|
||||
echo "trusted-key $KEY_ID" >> ~/.gnupg/gpg.conf
|
||||
|
||||
# Initialize the password store
|
||||
pass init $KEY_ID &>/dev/null
|
||||
|
||||
- name: Checkout ${{ matrix.folder_name }} repo
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
repository: ${{ matrix.github_repo }}
|
||||
path: support/src/${{ matrix.folder_name }}
|
||||
token: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
|
||||
ref: ${{ matrix.boundary_branch }}
|
||||
|
||||
- name: GH fix for localhost resolution
|
||||
run: |
|
||||
cat /etc/hosts && echo "-----------"
|
||||
sudo sed -i 's/::1 *localhost ip6-localhost ip6-loopback/::1 ip6 -localhost ip6-loopback/g' /etc/hosts
|
||||
cat /etc/hosts
|
||||
ssh -V
|
||||
|
||||
echo "127.0.0.1 localhost boundary" | sudo tee -a /etc/hosts
|
||||
echo "127.0.0.1 localhost worker" | sudo tee -a /etc/hosts
|
||||
echo "127.0.0.1 localhost vault" | sudo tee -a /etc/hosts
|
||||
|
||||
- name: Set git config
|
||||
run: |
|
||||
git config --global url."https://oauth2:${{ secrets.ELEVATED_GITHUB_TOKEN }}@github.com".insteadOf "https://github.com"
|
||||
|
||||
- name: Install node dependencies
|
||||
run: |
|
||||
pnpm install --frozen-lockfile
|
||||
cd e2e-tests
|
||||
pnpm playwright install --with-deps
|
||||
|
||||
- name: Set up test infra
|
||||
id: infra
|
||||
run: |
|
||||
ssh-keygen -N '' -t ed25519 -f ~/.ssh/github_enos
|
||||
mkdir -p ./enos/terraform-plugin-cache
|
||||
echo ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} > ./support/src/${{matrix.folder_name}}/internal/ui/VERSION
|
||||
export ENOS_VAR_ui_build_override="oss" && \
|
||||
export ENOS_VAR_boundary_edition=${{ matrix.boundary_edition_short }} && \
|
||||
export ENOS_VAR_enos_user=$GITHUB_ACTOR && \
|
||||
export ENOS_VAR_aws_ssh_private_key_path=~/.ssh/github_enos && \
|
||||
export ENOS_VAR_boundary_license="${{ secrets.BOUNDARY_ENT_LICENSE }}" && \
|
||||
enos scenario launch --timeout 60m0s --chdir ./support/src/${{matrix.folder_name}}/enos ${{matrix.enos_scenario}} builder:local
|
||||
|
||||
- name: Move boundary binary
|
||||
run: |
|
||||
mv ./support/src/${{matrix.folder_name}}/bin/boundary /usr/local/bin/
|
||||
boundary version
|
||||
|
||||
- name: Run Tests
|
||||
run: |
|
||||
source <(bash ./support/src/${{matrix.folder_name}}/enos/scripts/test_e2e_env.sh)
|
||||
cd e2e-tests
|
||||
pnpm run ${{ matrix.test_command }} --reporter=html
|
||||
|
||||
- name: Upload Playwright report
|
||||
if: ${{ failure() }}
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
with:
|
||||
name: playwright-report-${{ matrix.boundary_edition }}
|
||||
path: e2e-tests/playwright-report
|
||||
|
||||
- name: Clean up test infra
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
export ENOS_VAR_boundary_edition=${{ matrix.boundary_edition_short }} && \
|
||||
export ENOS_VAR_enos_user=$GITHUB_ACTOR && \
|
||||
export ENOS_VAR_aws_ssh_private_key_path=~/.ssh/github_enos && \
|
||||
enos scenario destroy --timeout 60m0s --chdir ./support/src/${{matrix.folder_name}}/enos ${{matrix.enos_scenario}} builder:local
|
||||
|
||||
- name: Send Slack message on failure
|
||||
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
|
||||
if: ${{ failure() && github.repository == 'hashicorp/boundary-ui' }}
|
||||
with:
|
||||
method: chat.postMessage
|
||||
token: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
payload: |
|
||||
channel: ${{ secrets.SLACK_CHANNEL_ID }}
|
||||
text: ":x: admin ui e2e tests failed: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Branch:* ${{ github.repository }}:${{ github.head_ref }}"
|
||||
@@ -0,0 +1,128 @@
|
||||
name: Test E2E Desktop Client
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [labeled, opened, synchronize, reopened]
|
||||
paths:
|
||||
- 'ui/desktop/**'
|
||||
- 'e2e-tests/*'
|
||||
- 'e2e-tests/api-client/**'
|
||||
- 'e2e-tests/helpers/**'
|
||||
- 'e2e-tests/desktop/**'
|
||||
- '.github/workflows/test-e2e-desktop.yaml'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: test
|
||||
runs-on: ${{ fromJSON(vars.RUNNER_UBUNTU_22) }}
|
||||
env:
|
||||
ENOS_VAR_boundary_edition: "ent"
|
||||
ENOS_VAR_e2e_debug_no_run: true
|
||||
SETUP_CLI: true
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up pnpm
|
||||
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||
with:
|
||||
run_install: false
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "pnpm"
|
||||
cache-dependency-path: |
|
||||
pnpm-lock.yaml
|
||||
ui/desktop/electron-app/pnpm-lock.yaml
|
||||
|
||||
- name: Set up Terraform
|
||||
uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd
|
||||
|
||||
- name: Set up Enos
|
||||
uses: hashicorp/action-setup-enos@39a8f388434bea5eeba6649b99aa9949a55a1150
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Install Vault CLI
|
||||
run: |
|
||||
wget https://releases.hashicorp.com/vault/1.12.2/vault_1.12.2_linux_amd64.zip -O /tmp/vault.zip
|
||||
unzip /tmp/vault.zip -d /usr/local/bin
|
||||
|
||||
- name: Checkout boundary-enterprise
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
repository: hashicorp/boundary-enterprise
|
||||
# ref: ${{ github.event.inputs.boundary-enterprise-branch }}
|
||||
path: support/src/boundary-enterprise
|
||||
token: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
|
||||
|
||||
- name: GH fix for localhost resolution
|
||||
run: |
|
||||
cat /etc/hosts && echo "-----------"
|
||||
sudo sed -i 's/::1 *localhost ip6-localhost ip6-loopback/::1 ip6 -localhost ip6-loopback/g' /etc/hosts
|
||||
cat /etc/hosts
|
||||
ssh -V
|
||||
|
||||
echo "127.0.0.1 localhost boundary" | sudo tee -a /etc/hosts
|
||||
echo "127.0.0.1 localhost worker" | sudo tee -a /etc/hosts
|
||||
echo "127.0.0.1 localhost vault" | sudo tee -a /etc/hosts
|
||||
|
||||
# TODO: Build image ourselves in case we don't want to use latest?
|
||||
- name: Get Boundary docker image
|
||||
run: |
|
||||
docker pull hashicorp/boundary-enterprise:latest
|
||||
docker save hashicorp/boundary-enterprise:latest | gzip > /tmp/boundary-enterprise.zip
|
||||
|
||||
- name: Set up test infra
|
||||
id: infra
|
||||
run: |
|
||||
ssh-keygen -N '' -t ed25519 -f ~/.ssh/github_enos
|
||||
mkdir -p ./enos/terraform-plugin-cache
|
||||
export ENOS_VAR_enos_user=$GITHUB_ACTOR && \
|
||||
export ENOS_VAR_aws_ssh_private_key_path=~/.ssh/github_enos && \
|
||||
export ENOS_VAR_boundary_license="${{ secrets.BOUNDARY_ENT_LICENSE }}" && \
|
||||
export ENOS_VAR_boundary_docker_image_file=/tmp/boundary-enterprise.zip && \
|
||||
enos scenario launch --timeout 60m0s --chdir ./support/src/boundary-enterprise/enos e2e_ui_docker_ent builder:crt
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pnpm install --frozen-lockfile
|
||||
cd e2e-tests
|
||||
pnpm playwright install --with-deps
|
||||
|
||||
# Runner is headless so we need to enable a display to run the client
|
||||
- name: Run Tests
|
||||
run: |
|
||||
source <(bash ./support/src/boundary-enterprise/enos/scripts/test_e2e_env.sh)
|
||||
cd e2e-tests
|
||||
export DISPLAY=:99
|
||||
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
|
||||
pnpm run desktop
|
||||
|
||||
- name: Upload Playwright report
|
||||
if: ${{ failure() }}
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
with:
|
||||
name: playwright-report
|
||||
path: e2e-tests/playwright-report
|
||||
|
||||
- name: Clean up test infra
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
export ENOS_VAR_enos_user=$GITHUB_ACTOR && \
|
||||
export ENOS_VAR_aws_ssh_private_key_path=~/.ssh/github_enos && \
|
||||
enos scenario destroy --timeout 60m0s --chdir ./support/src/boundary-enterprise/enos e2e_ui_docker_ent builder:crt
|
||||
|
||||
- name: Send Slack message on failure
|
||||
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
|
||||
if: ${{ failure() && github.repository == 'hashicorp/boundary-ui' }}
|
||||
with:
|
||||
method: chat.postMessage
|
||||
token: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
payload: |
|
||||
channel: ${{ secrets.SLACK_CHANNEL_ID }}
|
||||
text: ":x: desktop client e2e tests failed: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Branch:* ${{ github.repository }}:${{ github.head_ref }}"
|
||||
@@ -0,0 +1,22 @@
|
||||
name: "Trigger Boundary Desktop release"
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
trigger-gha-release:
|
||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- name: Release description
|
||||
run: |
|
||||
echo "Triggering release with a TAG ${GITHUB_REF#refs/tags/}"
|
||||
- name: Trigger Release workflow in boundary-desktop-releases
|
||||
run: |
|
||||
export GITHUB_TOKEN="${{ secrets.ELEVATED_GITHUB_TOKEN }}"
|
||||
gh workflow run release.yml \
|
||||
--repo hashicorp/boundary-desktop-releases \
|
||||
--ref main \
|
||||
-f TAG="${GITHUB_REF#refs/tags/}"
|
||||
@@ -0,0 +1,6 @@
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
url_license = "https://github.com/hashicorp/boundary-ui/blob/main/LICENSE"
|
||||
url_project_website = "https://learn.hashicorp.com/tutorials/boundary/getting-started-desktop-app"
|
||||
url_source_repository = "https://github.com/hashicorp/boundary-ui"
|
||||
@@ -3,21 +3,21 @@ License text copyright (c) 2020 MariaDB Corporation Ab, All Rights Reserved.
|
||||
|
||||
Parameters
|
||||
|
||||
Licensor: International Business Machines Corporation (IBM)
|
||||
Licensed Work: The Licensed Work is (c) 2024 IBM Corp.
|
||||
Licensor: HashiCorp, Inc.
|
||||
Licensed Work: The Licensed Work is (c) 2024 HashiCorp, Inc.
|
||||
Additional Use Grant: You may make production use of the Licensed Work, provided
|
||||
Your use does not include offering the Licensed Work to third
|
||||
parties on a hosted or embedded basis in order to compete with
|
||||
IBM Corp's paid version(s) of the Licensed Work. For purposes
|
||||
HashiCorp's paid version(s) of the Licensed Work. For purposes
|
||||
of this license:
|
||||
|
||||
A "competitive offering" is a Product that is offered to third
|
||||
parties on a paid basis, including through paid support
|
||||
arrangements, that significantly overlaps with the capabilities
|
||||
of IBM Corp's paid version(s) of the Licensed Work. If Your
|
||||
of HashiCorp's paid version(s) of the Licensed Work. If Your
|
||||
Product is not a competitive offering when You first make it
|
||||
generally available, it will not become a competitive offering
|
||||
later due to IBM Corp releasing a new version of the Licensed
|
||||
later due to HashiCorp releasing a new version of the Licensed
|
||||
Work with additional capabilities. In addition, Products that
|
||||
are not provided on a paid basis are not competitive.
|
||||
|
||||
@@ -33,10 +33,10 @@ Additional Use Grant: You may make production use of the Licensed Work, provided
|
||||
|
||||
Hosting or using the Licensed Work(s) for internal purposes
|
||||
within an organization is not considered a competitive
|
||||
offering. IBM Corp considers your organization to include all
|
||||
offering. HashiCorp considers your organization to include all
|
||||
of your affiliates under common control.
|
||||
|
||||
For binding interpretive guidance on using IBM Corp products
|
||||
For binding interpretive guidance on using HashiCorp products
|
||||
under the Business Source License, please visit our FAQ.
|
||||
(https://www.hashicorp.com/license-faq)
|
||||
Change Date: Four years from the date the Licensed Work is published.
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
Threshold UI
|
||||
Copyright (c) 2026 CyberCove LLC
|
||||
|
||||
This repository is a community fork of "Boundary UI"
|
||||
(https://github.com/hashicorp/boundary-ui), the admin web UI and desktop
|
||||
client for HashiCorp Boundary.
|
||||
|
||||
Upstream work: Copyright (c) HashiCorp, Inc. 2020-2023;
|
||||
Copyright (c) IBM Corp. 2024-2026
|
||||
Upstream license: Business Source License 1.1 (see LICENSE)
|
||||
|
||||
The upstream LICENSE and per-file copyright / SPDX headers are retained
|
||||
unchanged. Modifications made in this fork are provided under the same
|
||||
license terms (BUSL-1.1), including its Additional Use Grant and Change
|
||||
Date as stated in LICENSE.
|
||||
|
||||
This project is an independent community effort. It is NOT affiliated with,
|
||||
endorsed by, or sponsored by HashiCorp, Inc. or IBM Corp. "HashiCorp",
|
||||
"Boundary", and related marks and logos are trademarks of their respective
|
||||
owners; they are used here only to describe the upstream origin of this work
|
||||
and to name the upstream CLI/API this software interoperates with. The
|
||||
upstream logos and brand art have been removed and replaced with plain
|
||||
placeholder marks.
|
||||
|
||||
Third-party components keep their own licenses (see pnpm-lock.yaml and the
|
||||
`pnpm compliance:licenses` script). The HashiCorp Design System packages
|
||||
(@hashicorp/design-system-components, -tokens, @hashicorp/flight-icons) are
|
||||
consumed unmodified from the public npm registry under their own licenses.
|
||||
@@ -1,41 +1,10 @@
|
||||
# Threshold UI Monorepo
|
||||
# Boundary UI Monorepo
|
||||

|
||||
|
||||

|
||||
|
||||
This monorepo contains multiple projects, including UIs and addons, used by
|
||||
Threshold (the admin web UI and the desktop client).
|
||||
|
||||
## About this fork
|
||||
|
||||
This repository is a community fork of
|
||||
[hashicorp/boundary-ui](https://github.com/hashicorp/boundary-ui), rebranded
|
||||
for the Threshold project (a community fork of Boundary CE). It is licensed
|
||||
under the upstream Business Source License 1.1 (see [LICENSE](LICENSE) and
|
||||
[NOTICE](NOTICE)) and is **not affiliated with, endorsed by, or sponsored by
|
||||
HashiCorp or IBM**.
|
||||
|
||||
What changed relative to upstream:
|
||||
|
||||
- User-visible product name is Threshold (window titles, menus, about dialog,
|
||||
installer/package names, app id `net.anhonesthost.cybercove.threshold`).
|
||||
API paths, field names, protocol strings and environment variable names are
|
||||
unchanged for compatibility with the server. The desktop client's persisted
|
||||
settings are copied from the former "Boundary" user-data directory on first
|
||||
launch.
|
||||
- The desktop client looks for a `threshold` CLI first, then `boundary`.
|
||||
- HashiCorp/IBM logos and brand art were removed and replaced with plain
|
||||
placeholder marks.
|
||||
- Nothing contacts HashiCorp services by default. The in-app updater, the
|
||||
"unsupported controller" release-metadata lookup, and the CLI bundling
|
||||
download are disabled until you configure your own hosts:
|
||||
`THRESHOLD_UPDATE_FEED_URL` (desktop build, updater feed),
|
||||
`THRESHOLD_RELEASES_METADATA_URL` / `THRESHOLD_RELEASES_PAGE_URL`
|
||||
(desktop build, release links) and `THRESHOLD_CLI_RELEASES_URL` /
|
||||
`THRESHOLD_CLI_ARCHIVE_PREFIX` (used with `SETUP_CLI=true` to bundle a CLI).
|
||||
- Documentation links still point at the upstream Boundary documentation,
|
||||
which is user-initiated only.
|
||||
- Upstream HashiCorp-internal GitHub workflows and release metadata were
|
||||
removed; CI lives in `.gitea/workflows/ci.yml`.
|
||||
|
||||
Upstream history, CHANGELOGs and copyright headers are preserved.
|
||||
Boundary.
|
||||
|
||||
This top-level repository provides limited common tasks, such as installation
|
||||
and commit assistance. However, most tasks must be executed from within a
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# unconventional js
|
||||
/blueprints/*/files/
|
||||
|
||||
# compiled output
|
||||
/declarations/
|
||||
/dist/
|
||||
|
||||
# misc
|
||||
/coverage/
|
||||
!.*
|
||||
.*/
|
||||
|
||||
# ember-try
|
||||
/.node_modules.ember-try/
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
parser: '@babel/eslint-parser',
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
// This is specific babel-config. If grows consider creating a babel config file
|
||||
requireConfigFile: false,
|
||||
babelOptions: {
|
||||
plugins: [
|
||||
['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: true }],
|
||||
],
|
||||
},
|
||||
// end of babel-config
|
||||
},
|
||||
plugins: ['ember'],
|
||||
extends: ['eslint:recommended', 'plugin:ember/recommended', 'prettier'],
|
||||
env: {
|
||||
browser: true,
|
||||
},
|
||||
rules: {
|
||||
curly: ['error', 'multi-line', 'consistent'],
|
||||
'ember/no-get': 'off',
|
||||
'ember/no-get-with-default': 'off',
|
||||
'ember/no-computed-properties-in-native-classes': 'off',
|
||||
'ember/no-assignment-of-untracked-properties-used-in-tracking-contexts':
|
||||
'off',
|
||||
},
|
||||
overrides: [
|
||||
// node files
|
||||
{
|
||||
files: [
|
||||
'./.eslintrc.js',
|
||||
'./.prettierrc.js',
|
||||
'./.template-lintrc.js',
|
||||
'./ember-cli-build.js',
|
||||
'./index.js',
|
||||
'./testem.js',
|
||||
'./blueprints/*/index.js',
|
||||
'./config/**/*.js',
|
||||
'./tests/dummy/config/**/*.js',
|
||||
'./broccoli-plugins/**/*.js',
|
||||
],
|
||||
parserOptions: {
|
||||
sourceType: 'script',
|
||||
},
|
||||
env: {
|
||||
browser: false,
|
||||
node: true,
|
||||
},
|
||||
extends: ['plugin:n/recommended'],
|
||||
},
|
||||
{
|
||||
// test files
|
||||
files: ['tests/**/*-test.{js,ts}'],
|
||||
extends: ['plugin:qunit/recommended'],
|
||||
rules: {
|
||||
'qunit/require-expect': [2, 'except-simple'],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
+5
-38
@@ -21,50 +21,17 @@ This addon contains the API data access layer for Boundary.
|
||||
## Add API to an App
|
||||
|
||||
Add this addon to an Ember application's `devDependencies` as:
|
||||
`"api": "workspace:*"`, for applications included in this monorepo.
|
||||
`"api": "workspace:*"`, for applications included in this monorepo.
|
||||
|
||||
This addon also includes Mirage mocks. To include the `miragejs` dependency and this addon's mirage handlers configure the consuming app's `config/environment.js`
|
||||
Since this addon also includes Mirage mocks, be sure to install
|
||||
`ember-cli-mirage` and add the following config to your UI project:
|
||||
|
||||
```js
|
||||
mirage: {
|
||||
enabled: true
|
||||
'ember-cli-mirage': {
|
||||
directory: '../../addons/api/mirage'
|
||||
}
|
||||
```
|
||||
|
||||
Include `miragejs` and any api addon `peerDependencies` used by the mirage as dev dependencies in the consuming app,
|
||||
eg: `@faker-js/faker`, otherwise mirage handler code might fail with an error.
|
||||
|
||||
To have mirage start and intercept requests when the application starts:
|
||||
1. Add the `@embroider/macros` dependency to your application
|
||||
2. Configure `@embroider/macros` with `startMirageWithApp` based on app's config within `ember-cli-build.js`:
|
||||
|
||||
```js
|
||||
// ember-cli-build.js
|
||||
module.exports = async function (defaults) {
|
||||
// load the app's config
|
||||
const { EMBER_ENV } = process.env;
|
||||
var config = require('./config/environment')(EMBER_ENV);
|
||||
|
||||
const app = new EmberApp(defaults, {
|
||||
'@embroider/macros': {
|
||||
setOwnConfig: {
|
||||
startMirageWithApp: config.mirage?.enabled ?? false
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
3. Finally, use the `@embroider/macros` config value for `startMirageWithApp` in `app/app.js` to conditionally start mirage:
|
||||
|
||||
```js
|
||||
import { macroCondition, importSync, getOwnConfig, isTesting } from '@embroider/macros';
|
||||
|
||||
if (macroCondition(getOwnConfig().startMirageWithApp && !isTesting())) {
|
||||
const startServer = importSync('[name of host app]/mirage/config').default;
|
||||
startServer({});
|
||||
}
|
||||
```
|
||||
## Installation
|
||||
|
||||
See monorepo README for installation instructions.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
@@ -11,7 +11,7 @@ import { underscore } from '@ember/string';
|
||||
|
||||
/**
|
||||
* This test helper can be used to help setup your sinon stubs in your tests.
|
||||
* Must be called after setupMirage and setupDesktopContextBridgeApiMock in tests.
|
||||
* Must be called after setupMirage.
|
||||
*
|
||||
* ```js
|
||||
* import setupStubs from 'api/test-support/handlers/cache-daemon-search';
|
||||
@@ -19,15 +19,14 @@ import { underscore } from '@ember/string';
|
||||
* module('Acceptance | my test', function(hooks) {
|
||||
* setupApplicationTest(hooks);
|
||||
* setupMirage(hooks);
|
||||
* setupDesktopContextBridgeApiMock(hooks);
|
||||
* setupStubs(hooks);
|
||||
*
|
||||
* // add your actual tests here
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* This will setup a stub for window.desktop.daemon.searchCacheDaemon and include
|
||||
* helper methods to help setup what the cache daemon search command returns.
|
||||
* This will setup a stub for the IPC service and include helper methods to
|
||||
* help setup what the cache daemon search command returns.
|
||||
*
|
||||
* @module Test Helpers
|
||||
* @public
|
||||
@@ -36,6 +35,9 @@ export default function setupStubs(hooks) {
|
||||
let stubTypes = [];
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
const ipcService = this.owner.lookup('service:ipc');
|
||||
this.ipcStub = sinon.stub(ipcService, 'invoke');
|
||||
|
||||
/**
|
||||
* We aim to still use mirage data when stubbing out the cache daemon
|
||||
* search. However, the handler expects the search data to be raw JSON from
|
||||
@@ -54,32 +56,34 @@ export default function setupStubs(hooks) {
|
||||
stubTypes = types;
|
||||
|
||||
types.forEach((type, i) => {
|
||||
this.searchCacheDaemonStub.onCall(i).callsFake(() => {
|
||||
let models;
|
||||
let resourceName;
|
||||
if (typeOf(type) === 'object') {
|
||||
models = type.func();
|
||||
resourceName = type.resource;
|
||||
} else {
|
||||
models = this.server.schema[type].all().models;
|
||||
resourceName = type;
|
||||
}
|
||||
this.ipcStub
|
||||
.withArgs('searchCacheDaemon')
|
||||
.onCall(i)
|
||||
.callsFake(() => {
|
||||
let models;
|
||||
let resourceName;
|
||||
if (typeOf(type) === 'object') {
|
||||
models = type.func();
|
||||
resourceName = type.resource;
|
||||
} else {
|
||||
models = this.server.schema[type].all().models;
|
||||
resourceName = type;
|
||||
}
|
||||
|
||||
return {
|
||||
[underscore(resourceNames[singularize(resourceName)])]: models.map(
|
||||
(model) => {
|
||||
// Use internal serializer to serialize the model correctly
|
||||
// according to our mirage serializers
|
||||
const modelData =
|
||||
this.server.serializerOrRegistry.serialize(model);
|
||||
return {
|
||||
[underscore(resourceNames[singularize(resourceName)])]:
|
||||
models.map((model) => {
|
||||
// Use internal serializer to serialize the model correctly
|
||||
// according to our mirage serializers
|
||||
const modelData =
|
||||
this.server.serializerOrRegistry.serialize(model);
|
||||
|
||||
// Serialize the data properly to standard JSON as that is what
|
||||
// we're expecting from the cache daemon response
|
||||
return JSON.parse(JSON.stringify(modelData));
|
||||
},
|
||||
),
|
||||
};
|
||||
});
|
||||
// Serialize the data properly to standard JSON as that is what
|
||||
// we're expecting from the cache daemon response
|
||||
return JSON.parse(JSON.stringify(modelData));
|
||||
}),
|
||||
};
|
||||
});
|
||||
});
|
||||
};
|
||||
});
|
||||
@@ -87,19 +91,22 @@ export default function setupStubs(hooks) {
|
||||
hooks.afterEach(function () {
|
||||
// Verify the number of mocks we set up match with how
|
||||
// many times the cache daemon was called with
|
||||
sinon.assert.callCount(this.searchCacheDaemonStub, stubTypes.length);
|
||||
sinon.assert.callCount(
|
||||
this.ipcStub.withArgs('searchCacheDaemon'),
|
||||
stubTypes.length,
|
||||
);
|
||||
|
||||
stubTypes.forEach((type, i) => {
|
||||
// Assert that the stub was called with the resource we're trying to mock
|
||||
// so we don't mistakenly mock the wrong resource
|
||||
const call = this.searchCacheDaemonStub.getCall(i);
|
||||
const ipcCall = this.ipcStub.withArgs('searchCacheDaemon').getCall(i);
|
||||
let resource = type;
|
||||
if (typeOf(type) === 'object') {
|
||||
resource = type.resource;
|
||||
}
|
||||
|
||||
const mappedResourceName = resourceNames[singularize(resource)];
|
||||
sinon.assert.match(call.args[0], { resource: mappedResourceName });
|
||||
sinon.assert.match(ipcCall.args[1], { resource: mappedResourceName });
|
||||
});
|
||||
|
||||
sinon.restore();
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { settled } from '@ember/test-helpers';
|
||||
|
||||
export function createSetupMirage(startMirage) {
|
||||
return function setupMirage(hooks) {
|
||||
hooks.beforeEach(function () {
|
||||
if (!this.owner) {
|
||||
throw new Error(
|
||||
'Must call one of the ember-qunit setupTest() / setupRenderingTest() / setupApplicationTest() first',
|
||||
);
|
||||
}
|
||||
|
||||
// the environment property here is configuration to the mirage server:
|
||||
// https://github.com/miragejs/miragejs/blob/7ff4f3f6fe56bf0cb1648f5af3f5210fcb07e20b/types/index.d.ts#L383
|
||||
// It is not related to ember's build environment. In this case for mirage the "test" environment does
|
||||
// not load the default scenario:
|
||||
// https://github.com/miragejs/miragejs/blob/7ff4f3f6fe56bf0cb1648f5af3f5210fcb07e20b/lib/server.js#L302
|
||||
this.server = startMirage({ environment: 'test' });
|
||||
});
|
||||
|
||||
hooks.afterEach(function () {
|
||||
return settled().then(() => {
|
||||
if (this.server) {
|
||||
this.server.shutdown();
|
||||
delete this.server;
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
@@ -16,7 +16,7 @@ class InvalidRolePrincipalTypeError extends Error {
|
||||
export default class RoleAbility extends ModelAbility {
|
||||
// =services
|
||||
|
||||
@service abilities;
|
||||
@service can;
|
||||
|
||||
// =permissions
|
||||
|
||||
@@ -64,6 +64,6 @@ export default class RoleAbility extends ModelAbility {
|
||||
`Expected a role principal of type 'user', 'group', or 'managed-group'. Got '${type}'.`,
|
||||
);
|
||||
}
|
||||
return this.abilities.can(`read ${type}`, this.model);
|
||||
return this.can.can(`read ${type}`, this.model);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
@@ -131,34 +131,11 @@ export default class ApplicationAdapter extends RESTAdapter.extend(
|
||||
// which indicates that there are more items in the list
|
||||
// or the batch size has not been reached
|
||||
do {
|
||||
try {
|
||||
result = await super.query(store, schema, queryObject);
|
||||
} catch (e) {
|
||||
// If we hit a rate limit mid-pagination, return whatever
|
||||
// data has been accumulated so far rather than throwing and leaving
|
||||
// the user stuck with nothing to show.
|
||||
// Without a list_token this is the very first request with nothing to
|
||||
// show, so rethrow and let normal error handling apply.
|
||||
if (e?.errors?.[0]?.isRateLimited && queryObject.list_token) {
|
||||
result ??= {};
|
||||
result.items = data;
|
||||
result.response_type = 'complete';
|
||||
result.meta = {
|
||||
...result.meta,
|
||||
rateLimitWarning: { retryAfter: e.errors[0].retryAfter },
|
||||
};
|
||||
return prenormalizeArrayResponse(result);
|
||||
}
|
||||
|
||||
// For all other errors (or a 429 on the very first request with
|
||||
// no data yet), rethrow so normal error handling applies.
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Add the result items to a data array
|
||||
result = await super.query(store, schema, queryObject);
|
||||
//add the result items to a data array
|
||||
if (result && result.items) {
|
||||
data.push(...result.items);
|
||||
// Pass in the list token for subsequent calls to fetch the remaining list items
|
||||
//pass in the list token for subsequent calls to fetch the remaining list items
|
||||
queryObject.list_token = result.list_token;
|
||||
}
|
||||
} while (
|
||||
@@ -260,7 +237,6 @@ export default class ApplicationAdapter extends RESTAdapter.extend(
|
||||
* - `403 isForbidden`: the session is authenticated but does not have
|
||||
* permission to perform the requested action
|
||||
* - `404 isNotFound`: the requested resource could not be found
|
||||
* - `429 isRateLimited`: the client has exceeded the rate limit
|
||||
* - `500 isServer`: an internal server error occurred
|
||||
* - `isUnknown`: an error occurred, but we don't know which or
|
||||
* we don't distinguish it yet
|
||||
@@ -272,7 +248,7 @@ export default class ApplicationAdapter extends RESTAdapter.extend(
|
||||
* @param {Object} payload
|
||||
* @return {Array} errors payload
|
||||
*/
|
||||
normalizeErrorResponse(status, headers /*, payload*/) {
|
||||
normalizeErrorResponse(/*status, headers, payload*/) {
|
||||
const errors = super.normalizeErrorResponse(...arguments);
|
||||
if (isArray(errors)) {
|
||||
errors.forEach((error) => {
|
||||
@@ -286,14 +262,6 @@ export default class ApplicationAdapter extends RESTAdapter.extend(
|
||||
case 404:
|
||||
error.isNotFound = true;
|
||||
break;
|
||||
case 429:
|
||||
error.isRateLimited = true;
|
||||
// Attach rate-limit metadata from response headers so downstream
|
||||
// error handlers can inform the user when they may retry.
|
||||
error.retryAfter = Number(
|
||||
headers['Retry-After'] ?? headers['retry-after'],
|
||||
);
|
||||
break;
|
||||
case 500:
|
||||
error.isServer = true;
|
||||
break;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
@@ -23,7 +23,7 @@ export default class HostCatalogAdapter extends ApplicationAdapter {
|
||||
try {
|
||||
const pluginName = snapshot.attr('plugin')?.name;
|
||||
if (pluginName) url = `${url}?plugin_name=${pluginName}`;
|
||||
} catch {
|
||||
} catch (e) {
|
||||
// Ignore any adapter errors here
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
@@ -23,7 +23,7 @@ export default class SessionRecordingAdapter extends ApplicationAdapter {
|
||||
let method;
|
||||
try {
|
||||
method = snapshot?.adapterOptions?.method;
|
||||
} catch {
|
||||
} catch (e) {
|
||||
// Ignore any adapter errors here
|
||||
}
|
||||
if (method === 'download') {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
@@ -22,7 +22,7 @@ export default class StorageBucketAdapter extends ApplicationAdapter {
|
||||
let pluginName;
|
||||
try {
|
||||
pluginName = snapshot?.attr('plugin')?.name;
|
||||
} catch {
|
||||
} catch (e) {
|
||||
// Ignore any adapter errors here
|
||||
}
|
||||
if (requestType === 'createRecord' && pluginName) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
@@ -72,7 +72,7 @@ export default class GeneratedHostCatalogModel extends BaseModel {
|
||||
@attr('string', {
|
||||
for: {
|
||||
type: 'plugin',
|
||||
name: ['aws', 'azure', 'gcp'],
|
||||
name: ['aws', 'gcp'],
|
||||
},
|
||||
description:
|
||||
'An expression used to filter the workers that have network access to a service that is hosting the external object store.',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
@@ -96,34 +96,6 @@ export default class GeneratedSessionRecordingModel extends BaseModel {
|
||||
})
|
||||
duration;
|
||||
|
||||
@attr({
|
||||
description:
|
||||
'The detailed state of the session recording. This contains storage_state, syncing_error_details, and verification_error_details.',
|
||||
readOnly: true,
|
||||
})
|
||||
recording_state;
|
||||
|
||||
@attr('string', {
|
||||
description:
|
||||
'The availability of the session recording. One of "available" or "not available".',
|
||||
readOnly: true,
|
||||
})
|
||||
availability;
|
||||
|
||||
@attr('date', {
|
||||
description: 'The time until a session recording is required to be stored.',
|
||||
readOnly: true,
|
||||
})
|
||||
retain_until;
|
||||
|
||||
@attr('date', {
|
||||
description:
|
||||
'The time a session recording is scheduled to be automatically deleted.',
|
||||
readOnly: true,
|
||||
})
|
||||
delete_after;
|
||||
|
||||
// Deprecated: These two fields should be removed once support for RDP is added.
|
||||
@attr('string', {
|
||||
description:
|
||||
'The current state of the session recording. One of "started", "available" and "unknown".',
|
||||
@@ -137,4 +109,17 @@ export default class GeneratedSessionRecordingModel extends BaseModel {
|
||||
readOnly: true,
|
||||
})
|
||||
error_details;
|
||||
|
||||
@attr('date', {
|
||||
description: 'The time until a session recording is required to be stored.',
|
||||
readOnly: true,
|
||||
})
|
||||
retain_until;
|
||||
|
||||
@attr('date', {
|
||||
description:
|
||||
'The time a session recording is scheduled to be automatically deleted.',
|
||||
readOnly: true,
|
||||
})
|
||||
delete_after;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
@@ -59,6 +59,7 @@ const fetchControllerData = async (context, next) => {
|
||||
*/
|
||||
export default class CacheDaemonHandler {
|
||||
@service session;
|
||||
@service ipc;
|
||||
|
||||
constructor(context) {
|
||||
setOwner(this, getOwner(context));
|
||||
@@ -69,8 +70,9 @@ export default class CacheDaemonHandler {
|
||||
case 'query': {
|
||||
const { store, data } = context.request;
|
||||
const { type, query, options: { pushToStore = true } = {} } = data;
|
||||
const isCacheDaemonRunning =
|
||||
await window.desktop.daemon.isCacheDaemonRunning();
|
||||
const isCacheDaemonRunning = await this.ipc.invoke(
|
||||
'isCacheDaemonRunning',
|
||||
);
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
let { recursive, scope_id, page, pageSize, ...remainingQuery } = query;
|
||||
@@ -99,14 +101,6 @@ export default class CacheDaemonHandler {
|
||||
const token = sessionData?.token;
|
||||
const resourceName = resourceNames[type];
|
||||
|
||||
if (remainingQuery.query?.sort) {
|
||||
const { attribute, direction } = remainingQuery.query.sort;
|
||||
if (attribute && direction) {
|
||||
remainingQuery.sort_by = attribute;
|
||||
remainingQuery.sort_direction = direction;
|
||||
}
|
||||
}
|
||||
|
||||
remainingQuery = {
|
||||
...remainingQuery,
|
||||
query: searchQuery,
|
||||
@@ -117,19 +111,23 @@ export default class CacheDaemonHandler {
|
||||
|
||||
let cacheDaemonResults = {};
|
||||
try {
|
||||
cacheDaemonResults =
|
||||
await window.desktop.daemon.searchCacheDaemon(remainingQuery);
|
||||
cacheDaemonResults = await this.ipc.invoke(
|
||||
'searchCacheDaemon',
|
||||
remainingQuery,
|
||||
);
|
||||
} catch (e) {
|
||||
// If we got a 403, most likely the cache daemon was restarted and our token is no longer valid
|
||||
// I'm not sure if we can get a 401 since we always send a token but we'll handle it in the same way
|
||||
if (e.statusCode === 403 || e.statusCode === 401) {
|
||||
try {
|
||||
await window.desktop.daemon.addTokenToDaemons({
|
||||
await this.ipc.invoke('addTokenToDaemons', {
|
||||
tokenId: auth_token_id,
|
||||
token,
|
||||
});
|
||||
cacheDaemonResults =
|
||||
await window.desktop.daemon.searchCacheDaemon(remainingQuery);
|
||||
cacheDaemonResults = await this.ipc.invoke(
|
||||
'searchCacheDaemon',
|
||||
remainingQuery,
|
||||
);
|
||||
} catch (err) {
|
||||
// If it fails again just fall back to fetching controller data
|
||||
__electronLog?.error(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
@@ -59,39 +59,17 @@ export default class SqliteHandler {
|
||||
let payload,
|
||||
listToken,
|
||||
writeToDbPromise,
|
||||
totalInsert = 0,
|
||||
rateLimitWarning;
|
||||
totalInsert = 0;
|
||||
|
||||
if (!peekDb) {
|
||||
let tokenKey = `${type}-${hashCode(remainingQuery)}`;
|
||||
// The global token key represents a recursive query from global scope,
|
||||
// which pulls back every resource of this type.
|
||||
const globalTokenKey = `${type}-${hashCode({ scope_id: 'global', recursive: true })}`;
|
||||
const tokenKey = `${type}-${hashCode(remainingQuery)}`;
|
||||
if (storeToken) {
|
||||
// Always prefer the global token when it exists for
|
||||
// any more fine-grained query. The global query already fetched every
|
||||
// item for this resource type, so we should just re-use it.
|
||||
if (tokenKey !== globalTokenKey) {
|
||||
const [globalTokenObj] = await this.sqlite.fetchResource({
|
||||
...generateSQLExpressions('token', {
|
||||
filters: { id: [{ equals: globalTokenKey }] },
|
||||
}),
|
||||
});
|
||||
if (globalTokenObj?.token) {
|
||||
tokenKey = globalTokenKey;
|
||||
listToken = globalTokenObj.token;
|
||||
}
|
||||
}
|
||||
|
||||
// Only look up the specific token if no global token was found.
|
||||
if (!listToken) {
|
||||
const [tokenObj] = await this.sqlite.fetchResource({
|
||||
...generateSQLExpressions('token', {
|
||||
filters: { id: [{ equals: tokenKey }] },
|
||||
}),
|
||||
});
|
||||
listToken = tokenObj?.token;
|
||||
}
|
||||
const [tokenObj] = await this.sqlite.fetchResource({
|
||||
...generateSQLExpressions('token', {
|
||||
filters: { id: [{ equals: tokenKey }] },
|
||||
}),
|
||||
});
|
||||
listToken = tokenObj?.token;
|
||||
} else {
|
||||
// This is a temporary fix of clearing the DB (specifically for auth-methods)
|
||||
// since we are not storing the token we do not get back a list of removed_ids
|
||||
@@ -108,11 +86,6 @@ export default class SqliteHandler {
|
||||
});
|
||||
totalInsert += payload.items?.length ?? 0;
|
||||
|
||||
// Propagate any rate-limit warning the adapter attached
|
||||
if (payload.meta?.rateLimitWarning) {
|
||||
rateLimitWarning = payload.meta.rateLimitWarning;
|
||||
}
|
||||
|
||||
// await the previous writeToDbPromise before writing to db again
|
||||
if (writeToDbPromise) {
|
||||
await writeToDbPromise;
|
||||
@@ -190,14 +163,7 @@ export default class SqliteHandler {
|
||||
// This isn't conventional but is better than returning an ArrayProxy
|
||||
// or EmberArray since the ember store query method asserts it has to be an array
|
||||
// so we can't just return an object.
|
||||
records.meta = {
|
||||
totalItems: count[0].total,
|
||||
};
|
||||
|
||||
if (rateLimitWarning) {
|
||||
records.meta.rateLimitWarning = rateLimitWarning;
|
||||
}
|
||||
|
||||
records.meta = { totalItems: count[0].total };
|
||||
return records;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright IBM Corp. 2021, 2026
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
|
||||
Loaded 100 of 2336 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user