Compare commits

...
14 Commits
Author SHA1 Message Date
CyberCoveandClaude Sonnet 5.5 8e63f6bd0f ci: build admin test bundle once and run partitions against it
ci / check (push) Successful in 15m57s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 13:57:21 -07:00
CyberCoveandClaude Sonnet 5.5 01e50cb8ce ci: run admin test partitions sequentially (parallel browsers stalled on the runner)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 13:19:19 -07:00
CyberCoveandClaude Sonnet 5.5 1a97b8b428 ci: install chromium from the distro archive instead of downloading Chrome
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 12:53:16 -07:00
CyberCoveandClaude Sonnet 5.5 3f2be6fab0 Security: patch-level dependency overrides, electron 42.11.12; add Gitea CI
- Lockfile-only/overrides bumps within the same major for vulnerable
  transitive build/test tooling (see pnpm-overrides.md)
- electron 42.0.1 -> 42.11.12 (same major) for runtime advisories
- .gitea/workflows/ci.yml: single job (build admin, tests, audit)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 12:42:41 -07:00
CyberCoveandClaude Sonnet 5.5 89089dbb9a Rebrand Boundary UI to Threshold; neutralize HashiCorp update/phone-home endpoints
- Product name, app id, installer names, translations, titles -> Threshold
- Desktop: look for threshold CLI first, then boundary; migrate legacy
  Boundary user-data dir; updater/release lookups disabled unless configured
- Remove HashiCorp/IBM logos and art (plain placeholder mark), GitHub
  release workflows and HashiCorp release metadata
- Add NOTICE and README 'About this fork'

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-12 12:24:16 -07:00
richardtrinh1 25d78b2fc5 chore(deps): upgrade fast-uri to 3.1.8 (#3352) 2026-09-29 10:36:51 -05:00
Zhihe Li 4565676d4b chore: 🤖 Remove merge trigger for ENT (#3351) 2026-09-21 16:07:07 -04:00
Zhihe Li ed9371fab7 chore: 🤖 Update CLI version to correct one (#3336) 2026-07-10 12:17:57 -04:00
Zhihe Li 68a01cfa3a chore: 🤖 Update CLI version (#3335) 2026-07-10 10:17:51 -04:00
Priya Patel b7129e38a8 fix: 🐛 credential library update (#3328)
* fix: 🐛 update credential library serializer

* test: 💍 adds acceptance test

* test: 💍 fix test

* fix: 🐛 fix test

* test: 💍 adds a11y ignore

* chore: 🤖 pr feedback
2026-07-08 14:38:48 -07:00
Lisbet Alvarez 26e27fd24b fix: 🐛 code mirror lint tooltip format issues (#3325)
* fix: 🐛 code mirror lint tooltip format issues

* refactor: 💡 add fallback for parent config

* refactor: 💡 use getOwner to retrieve actual app root element
2026-06-19 12:52:48 -07:00
Zhihe Li d0612c0a46 feat: 🎸 No-op linting errors should be warnings (#3326) 2026-06-19 15:15:58 -04:00
Zhihe Li 347107c109 feat: 🎸 Add discard modal for edit grants page (#3324) 2026-06-18 13:35:49 -04:00
Lisbet Alvarez 0dac4ccf47 Use codemirror tooltip extension to set parent to fix positioning bug (#3323)
* fix: 🐛 absolute positioning of cm tooltip in firefox

* docs: ✏️ add comment

* fix: 🐛 tooltip hidden in editor fullscreen mode & dark mode

* fix: 🐛 tooltip color in dark mode

* docs: ✏️ add comment
2026-06-18 09:59:38 -07:00
90 changed files with 2357 additions and 3157 deletions

No files matched your search

+91
View File
@@ -0,0 +1,91 @@
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)
-2
View File
@@ -1,2 +0,0 @@
# Anyone attached to this rule will always been assigned to a pull request
* @hashicorp/boundary-ui
-67
View File
@@ -1,67 +0,0 @@
---
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._
-7
View File
@@ -1,7 +0,0 @@
# Copyright IBM Corp. 2021, 2026
# 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.
-23
View File
@@ -1,23 +0,0 @@
---
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.
-6
View File
@@ -1,6 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
-30
View File
@@ -1,30 +0,0 @@
# Copyright IBM Corp. 2021, 2026
# 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/**/*"
-33
View File
@@ -1,33 +0,0 @@
# 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.
-95
View File
@@ -1,95 +0,0 @@
#!/usr/bin/env bash
# Copyright IBM Corp. 2021, 2026
# 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
-56
View File
@@ -1,56 +0,0 @@
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@2e1d749697dd1612b833dba4a722266286fbefcd # v2.1.2
with:
install-dependencies: true
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 #v6.0.8
with:
cache: true
cache_dependency_path: '**/pnpm-lock.yaml'
run_install: false
- 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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
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
-94
View File
@@ -1,94 +0,0 @@
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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 #v6.0.8
with:
cache: true
cache_dependency_path: '**/pnpm-lock.yaml'
run_install: false
- 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Build
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 #v6.0.8
with:
run_install: false
cache: true
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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: admin-ui
path: ./ui/admin/dist/
- name: Upload artifact OSS admin UI
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Build
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 #v6.0.8
with:
run_install: false
cache: true
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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Build
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 #v6.0.8
with:
run_install: false
cache: true
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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: admin-ui-hcp
path: ./ui/admin/dist/
-62
View File
@@ -1,62 +0,0 @@
# 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
# 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
-19
View File
@@ -1,19 +0,0 @@
name: Add Copyright Headers
on: pull_request
jobs:
copywrite:
runs-on: ${{ fromJSON(vars.RUNNER) }}
permissions:
contents: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# 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@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0
with:
commit_message: Add missing copyright headers
-11
View File
@@ -1,11 +0,0 @@
name: "Pull Request Labeler"
on:
- pull_request_target
jobs:
triage:
runs-on: ${{ fromJSON(vars.RUNNER) }}
steps:
- uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213 # v6.1.0
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
-74
View File
@@ -1,74 +0,0 @@
name: Validate Monorepo
on: pull_request
jobs:
dependencies:
name: Install dependencies
runs-on: ${{ fromJSON(vars.RUNNER) }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 #v6.0.8
with:
cache: true
cache_dependency_path: '**/pnpm-lock.yaml'
run_install: false
- run: pnpm install --frozen-lockfile
compliance:
name: License Compliance
needs: [dependencies]
runs-on: ${{ fromJSON(vars.RUNNER) }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 #v6.0.8
with:
run_install: false
cache: true
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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 #v6.0.8
with:
run_install: false
cache: true
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@2e1d749697dd1612b833dba4a722266286fbefcd # v2.1.2
with:
install-dependencies: true
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 #v6.0.8
with:
run_install: false
cache: true
cache_dependency_path: '**/pnpm-lock.yaml'
- run: pnpm install --offline
- run: pnpm test
@@ -1,25 +0,0 @@
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"
-24
View File
@@ -1,24 +0,0 @@
name: OSS → ENT Merge
on:
repository_dispatch:
types: [ oss-merge ]
jobs:
oss-merge:
runs-on: ${{ fromJSON(vars.RUNNER) }}
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
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}}
-340
View File
@@ -1,340 +0,0 @@
name: Test E2E Admin UI
on:
pull_request:
types: [labeled, opened, synchronize, reopened]
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:
setup:
name: setup matrix
# don't need to run e2e tests on ce -> ent merges since tests were already
# run in the ce branch, and there are currently no code differences between
# the two repos
if: github.actor != 'hc-github-team-secure-boundary'
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Set matrix
id: set-matrix
run: |
BOUNDARY_BRANCH="${{ github.event.inputs.boundary-branch || 'main' }}"
ENT_BRANCH="${{ github.event.inputs.boundary-enterprise-branch || 'main' }}"
if [[ "${{ github.repository }}" == "hashicorp/boundary-ui" ]]; then
matrix=$(jq -cn --arg branch "$BOUNDARY_BRANCH" '{
browser: ["chromium", "firefox", "webkit"],
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: $branch
}]
}')
else
matrix=$(jq -cn --arg branch "$ENT_BRANCH" '{
browser: ["chromium", "firefox", "webkit"],
include: [{
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: $branch
}]
}')
fi
echo "matrix=$matrix" >> "$GITHUB_OUTPUT"
test:
name: test
needs: setup
runs-on: ${{ fromJSON(vars.RUNNER_UBUNTU_22) }}
strategy:
matrix: ${{ fromJSON(needs.setup.outputs.matrix) }}
fail-fast: false
env:
ENOS_VAR_e2e_debug_no_run: true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Set up Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
- name: Set up pnpm
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 #v6.0.8
with:
cache: true
cache_dependency_path: |
pnpm-lock.yaml
ui/desktop/electron-app/pnpm-lock.yaml
run_install: false
- name: Set up Terraform
uses: hashicorp/setup-terraform@dfe3c3f87815947d99a8997f908cb6525fc44e9e
- name: Set up Enos
uses: hashicorp/action-setup-enos@6ec106c8f809fe645162d73bea565c65f3269907
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Vault CLI
run: |
wget https://releases.hashicorp.com/vault/1.17.6/vault_1.17.6_linux_amd64.zip -O /tmp/vault.zip
if [[ "${{ github.repository }}" == "hashicorp/boundary-ui" ]]; then
unzip -o -q /tmp/vault.zip -d /usr/local/bin
elif [[ "${{ github.repository }}" == "hashicorp/boundary-ui-enterprise" ]]; then
unzip -o -q /tmp/vault.zip -d "$HOME/bin"
fi
- 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
sudo apt-get update
sudo apt-get install -y pass
pass init $KEY_ID &>/dev/null
- name: Checkout ${{ matrix.folder_name }} repo
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
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: |
if [[ "${{ github.repository }}" == "hashicorp/boundary-ui" ]]; then
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
fi
- name: Set git config
run: |
git config --global url."https://oauth2:${{ secrets.ELEVATED_GITHUB_TOKEN }}@github.com".insteadOf "https://github.com"
- name: Install Dependencies and Browsers
run: |
# Block Playwright from doing anything during the pnpm install
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 pnpm install --frozen-lockfile
cd e2e-tests
# Install browsers and dependencies based on the repository
if [[ "${{ github.repository }}" == "hashicorp/boundary-ui" ]]; then
pnpm playwright install --with-deps
elif [[ "${{ github.repository }}" == "hashicorp/boundary-ui-enterprise" ]]; then
# Use raw apt-get to install system libraries without npx
sudo apt-get install -y \
libnss3 \
libnspr4 \
libatk1.0-0 \
libatk-bridge2.0-0 \
libcups2 \
libdrm2 \
libdbus-1-3 \
libxcb1 \
libxkbcommon0 \
libx11-6 \
libxcomposite1 \
libxdamage1 \
libxext6 \
libxfixes3 \
libxrandr2 \
libgbm1 \
libpango-1.0-0 \
libcairo2 \
libasound2 \
libgtk-4-1 \
libgraphene-1.0-0 \
libevent-2.1-7 \
libopus0 \
libgstreamer-plugins-base1.0-0 \
libgstreamer-plugins-good1.0-0 \
libgstreamer-gl1.0-0 \
libgstreamer-plugins-bad1.0-0 \
libflite1 \
libwebpdemux2 \
libavif13 \
libwebpmux3 \
libmanette-0.2-0 \
libenchant-2-2 \
libhyphen0 \
libsecret-1-0 \
libwoff1 \
libx264-163 \
libsoup-3.0-0 \
gstreamer1.0-libav \
libicu70 \
libegl1 \
libepoxy0 \
libevdev2 \
libffi7 \
libfontconfig1 \
libfreetype6 \
libgdk-pixbuf-2.0-0 \
libgles2 \
libglib2.0-0 \
libglx0 \
libgstreamer1.0-0 \
libgudev-1.0-0 \
libharfbuzz-icu0 \
libharfbuzz0b \
libjpeg-turbo8 \
liblcms2-2 \
libnotify4 \
libopengl0 \
libopenjp2-7 \
libpng16-16 \
libproxy1v5 \
libwayland-client0 \
libwayland-egl1 \
libwayland-server0 \
libxml2 \
libxslt1.1 \
libatomic1
# Install the browser executables
pnpm playwright install
fi
- name: Determine Go version
id: get-go-version
run: |
echo "Building with Go $(cat ./support/src/${{matrix.folder_name}}/.go-version)"
echo "go-version=$(cat ./support/src/${{matrix.folder_name}}/.go-version)" >> "$GITHUB_OUTPUT"
- name: Set up Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ steps.get-go-version.outputs.go-version }}
cache: false
- name: Set up test infra
id: infra
run: |
ssh-keygen -N '' -t ed25519 -f ~/.ssh/github_enos
mkdir -p ./enos/terraform-plugin-cache
if [[ "${{ github.repository }}" == "hashicorp/boundary-ui" ]]; then
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"
elif [[ "${{ github.repository }}" == "hashicorp/boundary-ui-enterprise" ]]; then
echo ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} > ./support/src/${{matrix.folder_name}}/internal/ui/VERSION_ent
export ENOS_VAR_ui_build_override="enterprise"
fi
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: |
if [[ "${{ github.repository }}" == "hashicorp/boundary-ui" ]]; then
mv ./support/src/${{matrix.folder_name}}/bin/boundary /usr/local/bin/
elif [[ "${{ github.repository }}" == "hashicorp/boundary-ui-enterprise" ]]; then
mv ./support/src/${{matrix.folder_name}}/bin/boundary $HOME/bin
fi
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 }} --project=${{ matrix.browser}} --reporter=html
- name: Upload Playwright report
if: ${{ failure() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: playwright-report-${{ matrix.boundary_edition }}-${{ matrix.browser }}
path: e2e-tests/playwright-report
- name: Clean up test infra
if: ${{ always() }}
continue-on-error: true
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@45a88b9581bfab2566dc881e2cd66d334e621e2c # v3.0.3
if: ${{ failure() && github.repository == 'hashicorp/boundary-ui-enterprise' }}
with:
method: chat.postMessage
token: ${{ secrets.SLACK_BOT_TOKEN }}
payload: |
channel: ${{ secrets.SLACK_CHANNEL_ID }}
text: ":x: admin ui e2e tests (${{ matrix.boundary_edition }}:${{ matrix.browser }}) failed: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Branch:* ${{ github.repository }}:${{ github.head_ref || github.ref_name }}"
-184
View File
@@ -1,184 +0,0 @@
name: Test E2E Desktop Client
on:
pull_request:
types: [labeled, opened, synchronize, reopened]
workflow_dispatch:
inputs:
boundary-enterprise-branch:
description: 'Branch of boundary-enterprise to test against (default to main)'
required: true
default: 'main'
type: string
boundary-ui-enterprise-branch:
description: 'Branch of boundary-ui-enterprise to test against (default to main)'
required: true
default: 'main'
type: string
jobs:
test:
name: test
# don't need to run e2e tests on ce -> ent merges since tests were already
# run in the ce branch, and there are currently no code differences between
# the two repos
# desktop client e2e tests only run enterprise tests, so only run in boundary-ui-enterprise
if: github.actor != 'hc-github-team-secure-boundary' && github.repository == 'hashicorp/boundary-ui-enterprise'
runs-on: ${{ fromJSON(vars.RUNNER_UBUNTU_22) }}
env:
ENOS_VAR_boundary_edition: "ent"
ENOS_VAR_e2e_debug_no_run: true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Set up Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
- name: Set up pnpm
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 #v6.0.8
with:
cache: true
cache_dependency_path: |
pnpm-lock.yaml
ui/desktop/electron-app/pnpm-lock.yaml
run_install: false
- name: Set up Terraform
uses: hashicorp/setup-terraform@dfe3c3f87815947d99a8997f908cb6525fc44e9e
- name: Set up Enos
uses: hashicorp/action-setup-enos@6ec106c8f809fe645162d73bea565c65f3269907
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Vault CLI
run: |
wget https://releases.hashicorp.com/vault/1.17.6/vault_1.17.6_linux_amd64.zip -O /tmp/vault.zip
if [[ "${{ github.repository }}" == "hashicorp/boundary-ui" ]]; then
unzip -o -q /tmp/vault.zip -d /usr/local/bin
elif [[ "${{ github.repository }}" == "hashicorp/boundary-ui-enterprise" ]]; then
unzip -o -q /tmp/vault.zip -d "$HOME/bin"
fi
# TODO: We should consider modifying to also build CE binary. For now
# building ENT binary using most recent UI commit is sufficient.
- name: Checkout boundary-enterprise
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: hashicorp/boundary-enterprise
ref: ${{ github.event.inputs.boundary-enterprise-branch || 'main' }}
path: support/src/boundary-enterprise
token: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
- name: Checkout boundary-ui-enterprise
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: hashicorp/boundary-ui-enterprise
ref: ${{ github.event.inputs.boundary-ui-enterprise-branch || 'main' }}
path: support/src/boundary-ui-enterprise
token: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
- name: Use boundary-ui-enterprise commit SHA for building binary
run: |
cd support/src/boundary-ui-enterprise
git rev-parse HEAD > ../boundary-enterprise/internal/ui/VERSION_ent
- name: GH fix for localhost resolution
run: |
if [[ "${{ github.repository }}" == "hashicorp/boundary-ui" ]]; then
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
fi
- name: Set git config
run: |
git config --global url."https://oauth2:${{ secrets.ELEVATED_GITHUB_TOKEN }}@github.com".insteadOf "https://github.com"
- name: Determine Go version
id: get-go-version
run: |
echo "Building with Go $(cat ./support/src/boundary-enterprise/.go-version)"
echo "go-version=$(cat ./support/src/boundary-enterprise/.go-version)" >> "$GITHUB_OUTPUT"
- name: Set up Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ steps.get-go-version.outputs.go-version }}
cache: false
- 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_ui_build_override="ent" && \
export ENOS_VAR_boundary_edition="ent" && \
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/boundary-enterprise/enos e2e_ui_docker_ent builder:local
- name: Move boundary binary
run: |
if [[ "${{ github.repository }}" == "hashicorp/boundary-ui" ]]; then
mv ./support/src/boundary-enterprise/bin/boundary /usr/local/bin/
elif [[ "${{ github.repository }}" == "hashicorp/boundary-ui-enterprise" ]]; then
mv ./support/src/boundary-enterprise/bin/boundary $HOME/bin
fi
boundary version
- name: Install dependencies
run: |
pnpm install --frozen-lockfile
cd e2e-tests
if [[ "${{ github.repository }}" == "hashicorp/boundary-ui" ]]; then
pnpm playwright install --with-deps
elif [[ "${{ github.repository }}" == "hashicorp/boundary-ui-enterprise" ]]; then
# playwright dependencies can't be installed on a self-hosted runner
# due to permission issues
pnpm playwright install
sudo apt update -qq
sudo apt install xvfb -y
fi
# 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
Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
pnpm run desktop
- name: Upload Playwright report
if: ${{ failure() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: playwright-report
path: e2e-tests/playwright-report
- name: Clean up test infra
if: ${{ always() }}
continue-on-error: true
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:local
- name: Send Slack message on failure
uses: slackapi/slack-github-action@45a88b9581bfab2566dc881e2cd66d334e621e2c # v3.0.3
if: ${{ failure() && github.repository == 'hashicorp/boundary-ui-enterprise' }}
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 || github.ref_name }}"
-22
View File
@@ -1,22 +0,0 @@
name: "Trigger Boundary Desktop release"
on:
push:
tags:
- '*'
jobs:
trigger-gha-release:
runs-on: ${{ fromJSON(vars.RUNNER) }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- 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/}"
-6
View File
@@ -1,6 +0,0 @@
# Copyright IBM Corp. 2021, 2026
# 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"
+28
View File
@@ -0,0 +1,28 @@
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.
+36 -5
View File
@@ -1,10 +1,41 @@
# Boundary UI Monorepo
![](boundary.png)
![Validate Monorepo](https://github.com/hashicorp/boundary-ui/workflows/Validate%20Monorepo/badge.svg)
# Threshold UI Monorepo
This monorepo contains multiple projects, including UIs and addons, used by
Boundary.
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.
This top-level repository provides limited common tasks, such as installation
and commit assistance. However, most tasks must be executed from within a
@@ -68,21 +68,25 @@ export default class CredentialLibrarySerializer extends ApplicationSerializer {
*/
handleCredentialMappingOverrides(serialized, isNew) {
const { credential_type, credential_mapping_overrides } = serialized;
if (Object.keys(credential_mapping_overrides).length === 0) {
serialized.credential_mapping_overrides = null;
}
// API expects to send null to fields if it is undefined or deleted
if (credential_mapping_overrides && !isNew) {
serialized.credential_mapping_overrides = options.mapping_overrides[
credential_type
].reduce((obj, key) => {
if (credential_mapping_overrides[key]) {
obj[key] = credential_mapping_overrides[key];
} else {
obj[key] = null;
}
return obj;
}, {});
if (!credential_mapping_overrides || isNew || !credential_type) {
return;
}
// API expects to send null to fields if it is undefined or deleted
serialized.credential_mapping_overrides = options.mapping_overrides[
credential_type
].reduce((obj, key) => {
if (credential_mapping_overrides[key]) {
obj[key] = credential_mapping_overrides[key];
} else {
obj[key] = null;
}
return obj;
}, {});
}
}
+2 -2
View File
@@ -1,9 +1,9 @@
{
"name": "api",
"version": "0.0.0",
"description": "API data layer for Boundary.",
"description": "API data layer for Threshold.",
"license": "BUSL-1.1",
"author": "HashiCorp",
"author": "CyberCove LLC (fork of HashiCorp Boundary UI)",
"keywords": [
"ember-addon"
],
@@ -138,6 +138,45 @@ module('Unit | Serializer | credential library', function (hooks) {
});
});
test('it serializes credential library updates without credential_type', function (assert) {
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('credential-library');
store.push({
data: {
id: '1',
type: 'credential-library',
attributes: {
type: TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
name: 'Name',
description: 'Description',
path: '/vault/path',
http_method: 'GET',
version: 1,
credential_type: null,
credential_mapping_overrides: {},
},
},
});
const record = store.peekRecord('credential-library', '1');
const snapshot = record._createSnapshot();
const serializedRecord = serializer.serialize(snapshot);
assert.deepEqual(serializedRecord, {
type: TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
credential_store_id: null,
name: 'Name',
description: 'Description',
credential_type: null,
credential_mapping_overrides: null,
attributes: {
path: '/vault/path',
http_method: 'GET',
http_request_body: null,
},
version: 1,
});
});
test('it does not serialize http_request_body unless http_method is set to POST', function (assert) {
const store = this.owner.lookup('service:store');
const record = store.createRecord('credential-library', {
+2 -2
View File
@@ -1,9 +1,9 @@
{
"name": "auth",
"version": "0.0.0",
"description": "Authentication layer for Boundary.",
"description": "Authentication layer for Threshold.",
"license": "BUSL-1.1",
"author": "HashiCorp",
"author": "CyberCove LLC (fork of HashiCorp Boundary UI)",
"keywords": [
"ember-addon"
],
+4 -10
View File
@@ -1,12 +1,6 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 8C0 4.22876 0 2.34315 1.17157 1.17157C2.34315 0 4.22876 0 8 0H24C27.7712 0 29.6569 0 30.8284 1.17157C32 2.34315 32 4.22876 32 8V24C32 27.7712 32 29.6569 30.8284 30.8284C29.6569 32 27.7712 32 24 32H8C4.22876 32 2.34315 32 1.17157 30.8284C0 29.6569 0 27.7712 0 24V8Z" fill="url(#paint0_linear_4389_56864)"/>
<path d="M10.9261 25.03V23.6294H13.8501V22.7694H12.4249V21.3688H19.0838L15.9878 16.0123L19.0838 10.6557H12.2529V18.0763H8.5918V6.96997H21.2215L23.3347 10.6311L20.2387 16.0123L23.4084 21.4917L21.3444 25.03H10.9261Z" fill="white"/>
<path d="M11.4914 21.3688H10.0908V22.7694H11.4914V21.3688Z" fill="white"/>
<path d="M9.99237 23.6294H8.5918V25.03H9.99237V23.6294Z" fill="white"/>
<defs>
<linearGradient id="paint0_linear_4389_56864" x1="16" y1="0" x2="16" y2="32" gradientUnits="userSpaceOnUse">
<stop stop-color="#F66F74"/>
<stop offset="1" stop-color="#F34D52"/>
</linearGradient>
</defs>
<!-- Plain placeholder mark (not an official logo). -->
<rect width="32" height="32" rx="6" fill="#2b3a4a"/>
<rect x="7" y="7" width="18" height="4.5" fill="#fff"/>
<rect x="13.25" y="11.5" width="5.5" height="13.5" fill="#fff"/>
</svg>

Before

Width:  |  Height:  |  Size: 1009 B

After

Width:  |  Height:  |  Size: 341 B

+7 -68
View File
@@ -1,69 +1,8 @@
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 377 132">
<path
fill="#fff"
d="M125.45,41.34V35.68h-5.18v5.66h-2.64V27.75h2.64v5.7h5.18v-5.7h2.64V41.34Zm12.32,0h-2.09l-.19-.67a5.69,5.69,0,0,1-3,.87c-1.87,0-2.66-1.23-2.66-2.92,0-2,.9-2.75,3-2.75h2.46v-1c0-1.09-.32-1.47-1.95-1.47a14.85,14.85,0,0,0-2.83.3l-.32-1.87a14,14,0,0,1,3.5-.46c3.21,0,4.15,1.08,4.15,3.54Zm-2.55-3.7h-1.89c-.84,0-1.07.22-1.07,1s.23,1,1,1a4.1,4.1,0,0,0,1.93-.51Zm7.91,3.9a12.53,12.53,0,0,1-3.52-.56L140,39.1a11.5,11.5,0,0,0,3,.43c1.13,0,1.3-.24,1.3-1s-.12-.9-1.78-1.29c-2.49-.58-2.79-1.18-2.79-3.08s.9-2.83,3.82-2.83a14.07,14.07,0,0,1,3.06.34l-.25,2a19,19,0,0,0-2.81-.28c-1.11,0-1.3.24-1.3.84,0,.79.06.85,1.44,1.19,2.85.73,3.13,1.09,3.13,3.1S146.21,41.54,143.13,41.54Zm11.7-.2V34.5c0-.53-.23-.79-.81-.79a7.22,7.22,0,0,0-2.67.83v6.8H148.8V27.56l2.55.38v4.34a9.38,9.38,0,0,1,3.73-.94c1.7,0,2.31,1.14,2.31,2.89v7.11Zm4.71-11.19v-2.4h2.55v2.4Zm0,11.19v-9.8h2.55v9.8Zm4.6-9.72c0-2.46,1.48-3.88,5-3.88a16.63,16.63,0,0,1,3.8.44l-.3,2.19a21.49,21.49,0,0,0-3.41-.34c-1.83,0-2.41.6-2.41,2v5.15c0,1.43.58,2,2.41,2a21.57,21.57,0,0,0,3.41-.35l.3,2.2a16.63,16.63,0,0,1-3.8.44c-3.48,0-5-1.43-5-3.88Zm14.41,9.92c-3.5,0-4.45-1.85-4.45-3.86V35.2c0-2,1-3.86,4.45-3.86S183,33.19,183,35.2v2.48C183,39.69,182.05,41.54,178.55,41.54Zm0-8.11c-1.37,0-1.89.58-1.89,1.69v2.64c0,1.1.52,1.69,1.89,1.69s1.88-.59,1.88-1.69V35.12C180.43,34,179.91,33.43,178.55,33.43Zm11.64.16A20.64,20.64,0,0,0,187.48,35v6.32h-2.55v-9.8h2.16l.16,1.09a11.23,11.23,0,0,1,2.69-1.29Zm10.22,4.49c0,2.17-1,3.46-3.38,3.46a14.74,14.74,0,0,1-2.72-.28v4l-2.56.38V31.54h2l.25.82a5.54,5.54,0,0,1,3.22-1c2.06,0,3.15,1.16,3.15,3.4Zm-6.1,1.11a11.85,11.85,0,0,0,2.26.26c.93,0,1.28-.43,1.28-1.31V34.68c0-.81-.31-1.25-1.26-1.25a3.66,3.66,0,0,0-2.28.89Z">
</path>
<path
fill="#fff"
d="M139.64,70.53c3.08-1.33,4.48-3.21,4.48-6.53V59.82c0-5.45-3.09-8.59-10.72-8.59H117.55V91.52h16.94c7.33,0,11-3.56,11-9.25V78C145.51,74,143.33,71.31,139.64,70.53Zm-14.46-13h7.32c2.78,0,4,1,4,3.27v3.57c0,2.36-1.08,3.75-4.06,3.75h-7.25ZM137.89,81.3c0,3-1.46,3.93-4.91,3.93h-7.8v-11h8.47c3,0,4.24,1.33,4.24,4.06Z">
</path>
<path
fill="#fff"
d="M161.54,61.45c-10.11,0-12.82,5.57-12.82,11.62v7.44c0,6,2.71,11.62,12.82,11.62s12.83-5.57,12.83-11.62V73.07C174.37,67,171.64,61.45,161.54,61.45ZM167,80.76c0,3.32-1.51,5.08-5.45,5.08s-5.44-1.76-5.44-5.08V72.83c0-3.33,1.51-5.08,5.44-5.08S167,69.5,167,72.83Z">
</path>
<path
fill="#fff"
d="M196.51,62.06V82.51c-2.66,1.39-5.87,2.48-7.68,2.48s-2.36-.78-2.36-2.36V62.06h-7.38V83.42c0,5.26,1.75,8.71,6.65,8.71A29.44,29.44,0,0,0,197.54,89l.72,2.48h5.64V62.06Z">
</path>
<path
fill="#fff"
d="M228.4,61.45a29.61,29.61,0,0,0-11.8,3.09l-.72-2.48h-5.64V91.52h7.39V71.08c2.66-1.39,5.87-2.48,7.68-2.48s2.36.78,2.36,2.35V91.52h7.38V70.17C235.05,64.9,233.3,61.45,228.4,61.45Z">
</path>
<path
fill="#fff"
d="M257.5,50V62.31a40.19,40.19,0,0,0-7.87-.86c-6.83,0-9.74,3.88-9.74,10.41v10c0,6.71,3.15,10.22,9.08,10.22A15.49,15.49,0,0,0,258.29,89l.72,2.48h5.87V49Zm0,33.16a10.43,10.43,0,0,1-6.59,2.66c-2.73,0-3.63-1.33-3.63-3.75V71.68c0-2.66,1-3.93,3.68-3.93a32.33,32.33,0,0,1,6.54.79Z">
</path>
<path
fill="#fff"
d="M280.8,61.45a38.34,38.34,0,0,0-10.11,1.4l.91,5.62a41.47,41.47,0,0,1,8.17-.9c4.71,0,5.62,1.15,5.62,4.42v3.08h-7.08c-6,0-8.59,2.3-8.59,8.29,0,5.08,2.3,8.77,7.68,8.77a16.18,16.18,0,0,0,8.78-2.6l.54,2h6.06V72.1C292.78,64.72,290.05,61.45,280.8,61.45Zm4.59,23.3a11.57,11.57,0,0,1-5.56,1.51c-2.3,0-3-.91-3-3,0-2.23.67-2.9,3.09-2.9h5.44Z">
</path>
<path
fill="#fff"
d="M313,61.45a33,33,0,0,0-7.74,3.88l-.48-3.27h-6.24V91.52h7.38v-19a57.85,57.85,0,0,1,7.81-4.3Z">
</path>
<path
fill="#fff"
d="M335.67,62.06,328.9,84.44l-6.72-22.38h-7.56l9.32,29.46h2.59l-3.68,11.92h7l3.93-11.92,9.43-29.46Z">
</path>
<polygon
fill="#f04e54"
points="44.94 102.47 44.94 97.64 54.96 97.64 54.96 94.67 50.1 94.67 50.1 89.82 73.03 89.82 62.38 71.38 73.03 52.93 49.53 52.93 49.53 78.51 36.88 78.51 36.88 40.29 80.4 40.29 87.67 52.87 76.98 71.38 87.88 90.26 80.84 102.47 44.94 102.47">
</polygon>
<rect
fill="#f04e54"
x="42.04"
y="89.82"
width="4.85"
height="4.85">
</rect>
<rect
fill="#f04e54"
x="36.88"
y="97.61"
width="4.85"
height="4.85">
</rect>
<svg width="200" height="67" viewBox="0 0 200 67" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Threshold">
<!-- Plain placeholder wordmark (not an official logo). -->
<g class="logomark" fill="#ffffff">
<rect x="2" y="14" width="40" height="9"></rect>
<rect x="16.5" y="23" width="11" height="30"></rect>
</g>
<text class="logotype" x="54" y="43" fill="#ffffff" font-family="Helvetica, Arial, sans-serif" font-size="26" font-weight="600">Threshold</text>
</svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 491 B

+4 -68
View File
@@ -1,71 +1,7 @@
<svg
width="30"
height="30"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 67 67">
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<!-- Plain placeholder mark (not an official logo). -->
<g class="logomark">
<polygon
fill="#f04e54"
points="9.89 64.1 9.89 59.28 19.9 59.28 19.9 56.3 15.05 56.3 15.05 51.45 37.97 51.45 27.32 33.01 37.97 14.57 14.47 14.57 14.47 40.15 1.82 40.15 1.82 1.92 45.34 1.92 52.61 14.5 41.92 33.01 52.83 51.9 45.78 64.1 9.89 64.1">
</polygon>
<rect
fill="#f04e54"
x="6.98"
y="51.45"
width="4.85"
height="4.85">
</rect>
<rect
fill="#f04e54"
x="1.82"
y="59.25"
width="4.85"
height="4.85">
</rect>
</g>
<g class="logotype">
<path
fill="#ffffff"
d="M104.58,32.17c3.08-1.33,4.48-3.21,4.48-6.54V21.45c0-5.44-3.09-8.59-10.72-8.59H82.5v40.3H99.44c7.32,0,11-3.57,11-9.26V39.61C110.45,35.67,108.27,33,104.58,32.17Zm-14.46-13h7.32c2.78,0,4,1,4,3.27V26c0,2.36-1.08,3.76-4.05,3.76H90.12Zm12.71,23.78c0,3-1.46,3.94-4.91,3.94h-7.8v-11h8.47c3,0,4.24,1.33,4.24,4Z">
</path>
<path
fill="#ffffff"
d="M126.48,23.09c-10.1,0-12.82,5.56-12.82,11.62v7.44c0,6.05,2.72,11.61,12.82,11.61s12.83-5.56,12.83-11.61V34.71C139.31,28.65,136.58,23.09,126.48,23.09Zm5.45,19.3c0,3.33-1.51,5.08-5.45,5.08S121,45.72,121,42.39V34.47c0-3.34,1.51-5.09,5.44-5.09s5.45,1.75,5.45,5.09Z">
</path>
<path
fill="#ffffff"
d="M161.46,23.69V44.15c-2.67,1.39-5.88,2.48-7.69,2.48s-2.36-.79-2.36-2.37V23.69H144V45.05c0,5.27,1.75,8.71,6.65,8.71a29.59,29.59,0,0,0,11.8-3.08l.73,2.48h5.63V23.69Z">
</path>
<path
fill="#ffffff"
d="M193.34,23.09a29.59,29.59,0,0,0-11.8,3.08l-.72-2.48h-5.63V53.16h7.38V32.71c2.66-1.39,5.87-2.48,7.68-2.48s2.36.79,2.36,2.36V53.16H200V31.8C200,26.54,198.24,23.09,193.34,23.09Z">
</path>
<path
fill="#ffffff"
d="M222.44,11.66V23.94a41,41,0,0,0-7.87-.85c-6.83,0-9.73,3.87-9.73,10.41v10c0,6.72,3.14,10.22,9.07,10.22a15.48,15.48,0,0,0,9.32-3.08l.72,2.48h5.87V10.63Zm0,33.15a10.43,10.43,0,0,1-6.59,2.66c-2.73,0-3.63-1.33-3.63-3.75V33.32c0-2.67,1-3.94,3.69-3.94a33,33,0,0,1,6.53.79Z">
</path>
<path
fill="#ffffff"
d="M245.74,23.09a38.76,38.76,0,0,0-10.11,1.39l.91,5.63a40.74,40.74,0,0,1,8.17-.91c4.71,0,5.62,1.15,5.62,4.42V36.7h-7.07c-6,0-8.6,2.3-8.6,8.29,0,5.09,2.3,8.77,7.69,8.77a16.06,16.06,0,0,0,8.77-2.6l.54,2h6.06V33.74C257.72,26.35,255,23.09,245.74,23.09Zm4.59,23.29a11.57,11.57,0,0,1-5.56,1.51c-2.3,0-3-.9-3-3,0-2.24.67-2.9,3.09-2.9h5.44Z">
</path>
<path
fill="#ffffff"
d="M277.92,23.09A33,33,0,0,0,270.18,27l-.48-3.27h-6.24V53.16h7.39v-19a56,56,0,0,1,7.8-4.29Z">
</path>
<path
fill="#ffffff"
d="M300.61,23.69l-6.77,22.39-6.72-22.39h-7.56l9.32,29.47h2.59l-3.68,11.92h7l3.93-11.92,9.44-29.47Z">
</path>
<rect x="3" y="3" width="24" height="6" fill="currentColor"></rect>
<rect x="12" y="9" width="6" height="18" fill="currentColor"></rect>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 336 B

+3 -23
View File
@@ -1,24 +1,4 @@
<svg
width="30"
height="30"
viewBox="0 0 30 30"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<g class="logomark">
<path
d="M0 7.19579L11.4553 0.58728V5.55192L4.30398 9.68052V25.5537L0 23.069V7.19579Z"
fill="currentColor">
</path>
<path
d="M16.0285 0.58728V13.2291H11.4553V8.51084L7.15165 10.9956V27.1919L11.4553 29.6829V17.0771H16.0285V21.7641L20.3321 19.2788V3.07229L16.0285 0.58728Z"
fill="currentColor">
</path>
<path
d="M27.4838 23.0789L16.0285 29.6875V24.7228L23.1798 20.5939V4.72074L27.4838 7.20576V23.0789Z"
fill="currentColor">
</path>
</g>
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<!-- Plain placeholder (no company logo). -->
<rect x="3" y="3" width="24" height="24" rx="4" stroke="currentColor" stroke-width="2"></rect>
</svg>

Before

Width:  |  Height:  |  Size: 636 B

After

Width:  |  Height:  |  Size: 248 B

+14 -14
View File
@@ -27,7 +27,7 @@ titles:
action: Action
documentation: Documentation
abandon-confirm: Discard unsaved changes?
welcome-to-boundary: Welcome to Boundary
welcome-to-boundary: Welcome to Threshold
label: Label
value: Value
no-results: No Results
@@ -84,27 +84,27 @@ onboarding:
target-port: Default Port
target-setup-info: We’ll set up scopes for you
descriptions:
setup-first-target: In Boundary, a “target” defines a server that your users will connect to. We can help you set up your first target for proof-of-concept testing, or you can skip this step if you don’t want to do it right now.
setup-first-target: In Threshold, a “target” defines a server that your users will connect to. We can help you set up your first target for proof-of-concept testing, or you can skip this step if you don’t want to do it right now.
target-address: Host name or IP address.
target-port: The default port on which to connect.
target-setup-info: Targets live in projects, and projects live in orgs. We will create these example scopes for you but they can be edited or deleted later.
success:
titles:
connect: Connect to your target
desktop: Using Boundary Desktop
desktop: Using Threshold Desktop
developers: Developers
controller: Controller URL
creation-success: We have created your scopes and target
descriptions:
download: Download the Boundary Desktop app to browse and connect to targets (available for Windows, Mac, and Linux)
developers: You can also connect to targets using the Boundary CLI or API.
controller: Use this URL to sign in to Boundary
role: You can now connect to the target with the Boundary Desktop app, command-line (CLI) or API. Boundary grants access to resources based on roles, and we have added you to the `demo` role to give you access to this target. Make sure to add this role to any new users if you want them to access it too.
download: Download the Threshold Desktop app to browse and connect to targets (available for Windows, Mac, and Linux)
developers: You can also connect to targets using the Threshold CLI or API.
controller: Use this URL to sign in to Threshold
role: You can now connect to the target with the Threshold Desktop app, command-line (CLI) or API. Threshold grants access to resources based on roles, and we have added you to the `demo` role to give you access to this target. Make sure to add this role to any new users if you want them to access it too.
links:
install: Install the Boundary Desktop app
learn: Learn about Boundary Desktop app
cli: Learn about Boundary command-line (CLI)
api: Learn about Boundary API
install: Install the Threshold Desktop app
learn: Learn about Threshold Desktop app
cli: Learn about Threshold command-line (CLI)
api: Learn about Threshold API
unsupported-controller:
title: Unsupported controller version
description:
@@ -120,7 +120,7 @@ settings:
cli: CLI
cache-daemon: Cache Daemon
client-agent:
title: Boundary Client Agent
title: Threshold Client Agent
description: Required to use Transparent Sessions
client: Client
version: Version
@@ -130,7 +130,7 @@ settings:
self-managed: Self-managed
server:
title: Server
description: Boundary connects you to targets using this server managed by your organization.
description: Threshold connects you to targets using this server managed by your organization.
logs:
title: Logs
logging-level: Logging level
@@ -145,7 +145,7 @@ settings:
client-agent: There may be a problem with the client agent
preferred-clients:
title: Preferred Clients
description: Select the applications for Boundary to use when opening these target types.
description: Select the applications for Threshold to use when opening these target types.
table:
header:
protocol: Protocol
+6 -6
View File
@@ -55,7 +55,7 @@ session_id:
label: Session ID
worker_release_version:
label: Release Version
help: The version of the Boundary binary the worker is running.
help: The version of the Threshold binary the worker is running.
worker_authorized_actions:
label: Authorized Actions
worker_last_seen:
@@ -70,12 +70,12 @@ grant_scope:
help: Specify the scope to which this role applies.
cluster-url:
label: Cluster URL
description: The Boundary URL to which to connect (e.g. protocol://host:port)
description: The Threshold URL to which to connect (e.g. protocol://host:port)
proxy_url:
label: Proxy URL
issuer:
label: Issuer
help: The issuer URL. Boundary expects only the schema, host, and port and will strip off ".well-known/openid-configuration" if present. This will be used for configuration discovery as well as for validation of the "iss" claim.
help: The issuer URL. Threshold expects only the schema, host, and port and will strip off ".well-known/openid-configuration" if present. This will be used for configuration discovery as well as for validation of the "iss" claim.
client_id:
label: Client ID
help: An OAuth 2.0 Client Identifier valid at the Authorization Server.
@@ -159,7 +159,7 @@ secret_access_key:
help: The secret access key generated by AWS for the IAM user to use with this AWS Host Catalog.
secret:
label: Client Secret Value
help: The client secret value generated by Azure for Boundary to use for authentication.
help: The client secret value generated by Azure for Threshold to use for authentication.
disable_credential_rotation:
label: Disable credential rotation
help: Azure host catalogs do not yet support credential rotation.
@@ -173,7 +173,7 @@ ip_addresses:
help: Read-only public and private IP addresses given by the plugin host catalog provider
sync-interval:
label: Sync Interval
help: Number of seconds between the time Boundary syncs hosts in this set.
help: Number of seconds between the time Threshold syncs hosts in this set.
tags:
label: Tags
secret-editor:
@@ -184,6 +184,6 @@ created:
label: Created
other_fields:
label: Other Fields
help: This information is provided by the server and cannot be edited in Boundary
help: This information is provided by the server and cannot be edited in Threshold
worker_filter:
label: Worker Filter
+23 -23
View File
@@ -4,7 +4,7 @@
account:
title: Account
title_plural: Accounts
description: An account allows a user to log into Boundary with a particular auth method. Users may have multiple accounts for different auth methods.
description: An account allows a user to log into Threshold with a particular auth method. Users may have multiple accounts for different auth methods.
messages:
welcome:
title: Welcome to Accounts
@@ -167,13 +167,13 @@ auth-method:
help: This group includes inputs for configuring the LDAP server itself, such as the server name, port, and authentication settings.
authenticated-search:
title: Authenticated search
help: Used when Boundary authenticates to the LDAP server.
help: Used when Threshold authenticates to the LDAP server.
anonymous-search:
title: Anonymous search
help: Allows you to bind anonymously to the directory when searching for user entries.
user-entries:
title: User entries
help: Before authenticating an end user, Boundary must first find the end user’s entry in the directory.
help: Before authenticating an end user, Threshold must first find the end user’s entry in the directory.
group-entries:
title: Group entries
help: After authenticating an end user, we need to find out which groups the user is a member of. The configuration for this can vary depending on your LDAP server and your directory schema.
@@ -239,7 +239,7 @@ host-catalog:
help: AWS region of the hosts to be added to this AWS Host Catalog.
azure_client_id:
label: Client/Application ID
help: The client (application) ID of an Azure service principal that Boundary will use to authenticate and discover hosts from Azure.
help: The client (application) ID of an Azure service principal that Threshold will use to authenticate and discover hosts from Azure.
worker_filter:
help: Insert a worker filter in order to select the correct worker.
project_id:
@@ -302,7 +302,7 @@ host:
title: Host
title_plural: Hosts
no_name_title: Unnamed Host
description: A host is a resource that may be accessed by a Boundary target.
description: A host is a resource that may be accessed by a Threshold target.
details: Host Details
messages:
welcome:
@@ -323,7 +323,7 @@ session:
title: Session
title_plural: Sessions
active_plural: Active Sessions
description: A session is a connection to a target initiated through Boundary.
description: A session is a connection to a target initiated through Threshold.
remaining: remaining
status:
active: Active
@@ -344,7 +344,7 @@ session:
title: Connected
description: You can now access {targetDisplayName}
stop-sessions-and-signout:
title: Sign out of Boundary?
title: Sign out of Threshold?
description: Signing out will stop all active and pending target sessions. Are you sure you want to sign out?
stop-sessions-before-quit:
title: Close sessions before quitting?
@@ -539,7 +539,7 @@ storage-bucket:
help: Filters to the worker(s) that can handle requests for this storage bucket.
disable_credential_rotation:
label: Disable credential rotation
help: Disabling credential rotation could allow entities outside of Boundary to know the client secret in use.
help: Disabling credential rotation could allow entities outside of Threshold to know the client secret in use.
questions:
delete-storage-bucket:
title: Delete associated recordings?
@@ -560,7 +560,7 @@ project:
user:
title: User
title_plural: Users
description: Users are entities authorized to access Boundary. Users may be assigned to roles as principals, thus receiving role grants.
description: Users are entities authorized to access Threshold. Users may be assigned to roles as principals, thus receiving role grants.
messages:
welcome:
title: Welcome to Users
@@ -634,7 +634,7 @@ role:
templates:
global-admin:
name: Global Admin
description: Full administrative access to all resources in Boundary
description: Full administrative access to all resources in Threshold
org-access:
name: Org Access
description: Administrative access to perform actions on an org scope, but not the resources the org contains
@@ -805,10 +805,10 @@ role:
add-worker-tags: Add tags to a worker
set-worker-tags: Set the full list of tags on a worker
remove-worker-tags: Remove tags from a worker
reinitialize-certificate-authority: Reinitialize the certificate authority that is used to authorize Boundary workers
reinitialize-certificate-authority: Reinitialize the certificate authority that is used to authorize Threshold workers
create:controller-led: Create a worker via controller-led workflow
create:worker-led: Create a worker via worker-led workflow
read-certificate-authority: Read the certificate authority that is used to authorize Boundary workers
read-certificate-authority: Read the certificate authority that is used to authorize Threshold workers
set-password: Set a password on an account, without requiring the current password
change-password: Change the password on an account
authenticate: Authenticate to an auth method
@@ -846,7 +846,7 @@ role:
list-exports: List all export jobs for session recordings
export: Export a session recording
export:cancel: Cancel an in-progress session recording export
monthly-active-users: Display the number of monthly active Boundary users to help predict billing
monthly-active-users: Display the number of monthly active Threshold users to help predict billing
no-actions: No actions available for this resource type.
invalid-id-or-type: Invalid ID and type. No actions available.
no-type-detected: No resource type detected.
@@ -936,7 +936,7 @@ target:
title: Welcome to Targets
none:
title: No Targets Available
description: No Targets to display yet. Contact your Boundary admin if you don't see a Target you expect access to.
description: No Targets to display yet. Contact your Threshold admin if you don't see a Target you expect access to.
connection-success:
title: Successfully Connected
connection-details:
@@ -1053,10 +1053,10 @@ target:
description: Select injected Application credential sources to assign to this target.
alert:
title: Cannot connect to this target without injected application credentials
description: Injected application credentials are used by Boundary to sign in to remote resources without showing them to the end-user.
description: Injected application credentials are used by Threshold to sign in to remote resources without showing them to the end-user.
action: Add injected application credentials
workers:
description: You can customize how your workers route traffic to this target by setting up a filter that matches specific worker tags. If your target is in a private network, we recommend setting up an egress filter to specify a worker inside the network so that Boundary can access the host. Ingress and egress filters are allowed to select the same worker.
description: You can customize how your workers route traffic to this target by setting up a filter that matches specific worker tags. If your target is in a private network, we recommend setting up an egress filter to specify a worker inside the network so that Threshold can access the host. Ingress and egress filters are allowed to select the same worker.
messages:
none:
description: You haven't added an {type} worker filter yet.
@@ -1082,7 +1082,7 @@ target:
description: Specify workers that have access to the target (such as within a private network).
edit-ingress-worker-filter:
title: Edit Ingress Worker Filter
description: Specify workers Boundary should use to start the route to this target.
description: Specify workers Threshold should use to start the route to this target.
worker-filter:
description: The worker filter format for this target.
accordion-label:
@@ -1098,7 +1098,7 @@ credential-store:
titles:
new: New Credential Store
worker-filter:
description: A filter used to control which PKI workers can handle Vault requests, allowing the use of private Vault instances with Boundary.
description: A filter used to control which PKI workers can handle Vault requests, allowing the use of private Vault instances with Threshold.
messages:
none:
description: You haven't added a worker filter yet.
@@ -1342,20 +1342,20 @@ worker:
view_more: View more tags
form:
cluster_id:
label: Boundary Cluster ID
label: Threshold Cluster ID
help: The cluster ID is the UUID in the HCP Boundary Controller URL.
ip_address:
label: Worker public address
help: Public IP or address.
initial_upstreams:
label: Initial Upstreams
help: A list of hosts/IP addresses and optionally ports for reaching Boundary cluster. The port will default to :9201 if not specified.
help: A list of hosts/IP addresses and optionally ports for reaching Threshold cluster. The port will default to :9201 if not specified.
config_file_path:
label: Config file path
help: The path on your server where you will store your configuration file.
worker_tags:
label: Worker Tags
help: Boundary can use tags to define key-value pairs which targets can use to determine where they should route connections.
help: Threshold can use tags to define key-value pairs which targets can use to determine where they should route connections.
local_session_recording_storage:
label: Local Session Recording Storage
help: To record sessions using this worker, specify a local storage path and ensure that it is provisioned with sufficient capacity. In progress recordings are stored locally until they complete, and then moved to the remote storage bucket associated with their target.
@@ -1371,8 +1371,8 @@ worker:
create_config: 'Open the file with a text editor, such as Vi. Paste the following configuration into the worker config file:'
save_config: Save the configuration in your <code>pki-worker.hcl</code> file.
2:
title: 2. Install & start Boundary on your server
run_command: 'Run this command on your server to install Boundary:'
title: 2. Install & start Threshold on your server
run_command: 'Run this command on your server to install Threshold:'
copy_registration_request: When the server starts, it will print details related to this worker. Copy the value for
3:
title: 3. Confirm the worker when they connect
@@ -203,30 +203,30 @@
// Overrides for CodeMirror 6 autocomplete and lint tooltips/panels.
@mixin dark-mode-codemirror-override {
/* stylelint-disable selector-class-pattern */
// Autocomplete dropdown and lint hover tooltips
.cm-tooltip {
background-color: var(--token-color-palette-neutral-50);
border: 1px solid var(--token-color-palette-neutral-100);
color: var(--token-color-palette-neutral-400);
}
// Arrow pointer for tooltips shown above the cursor
.cm-tooltip-above::before {
border-top-color: var(--token-color-palette-neutral-50);
}
// Arrow pointer for tooltips shown below the cursor
.cm-tooltip-below::before {
border-bottom-color: var(--token-color-palette-neutral-50);
}
// Autocomplete list > selected item highlight
.cm-tooltip-autocomplete > ul > li[aria-selected] {
background-color: var(--token-color-palette-blue-300);
color: var(--token-color-palette-neutral-700);
}
.cm-editor {
// Autocomplete dropdown and lint hover tooltips
.cm-tooltip {
background-color: var(--token-color-palette-neutral-50);
border: 1px solid var(--token-color-palette-neutral-100);
color: var(--token-color-palette-neutral-400);
}
// Arrow pointer for tooltips shown above the cursor
.cm-tooltip-above::before {
border-top-color: var(--token-color-palette-neutral-50);
}
// Arrow pointer for tooltips shown below the cursor
.cm-tooltip-below::before {
border-bottom-color: var(--token-color-palette-neutral-50);
}
// Autocomplete list > selected item highlight
.cm-tooltip-autocomplete > ul > li[aria-selected] {
background-color: var(--token-color-palette-blue-300);
color: var(--token-color-palette-neutral-700);
}
// Content/gutter border
.cm-content {
border-left: 1px solid var(--token-color-palette-neutral-100);
+2 -2
View File
@@ -1,9 +1,9 @@
{
"name": "rose",
"version": "0.0.0",
"description": "Styles and components for Boundary.",
"description": "Styles and components for Threshold.",
"license": "BUSL-1.1",
"author": "HashiCorp",
"author": "CyberCove LLC (fork of HashiCorp Boundary UI)",
"keywords": [
"ember-addon"
],
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

+1 -1
View File
@@ -2,7 +2,7 @@
"name": "e2e-tests",
"version": "0.0.0",
"description": "End to end tests for boundary UI",
"author": "HashiCorp",
"author": "CyberCove LLC (fork of HashiCorp Boundary UI)",
"license": "BUSL-1.1",
"private": true,
"type": "module",
+39 -4
View File
@@ -1,8 +1,8 @@
{
"private": true,
"description": "Monorepo for Boundary UIs and addons.",
"description": "Monorepo for Threshold UIs and addons.",
"license": "BUSL-1.1",
"author": "HashiCorp",
"author": "CyberCove LLC (fork of HashiCorp Boundary UI)",
"scripts": {
"build": "pnpm build:ui:admin",
"build:ui:admin": "pnpm run --filter admin build",
@@ -52,9 +52,44 @@
"ember-try-config>package-json": "^10.0.1",
"ember-loading>ember-concurrency": "^4.0.0",
"tmp": "^0.2.7",
"tar": "^7.5.10",
"tar": "^7.5.22",
"nomnom>underscore": "^1.13.8",
"ember-cli>markdown-it": "^14.2.0"
"ember-cli>markdown-it": "^14.3.2",
"diff@>=5.0.0 <6.0.0": "^5.2.2",
"qs@>=6.0.0 <7.0.0": "^6.16.0",
"follow-redirects@>=1.0.0 <2.0.0": "^1.16.1",
"postcss@>=8.0.0 <9.0.0": "^8.5.29",
"ws@>=8.0.0 <9.0.0": "^8.22.0",
"brace-expansion@>=5.0.0 <6.0.0": "^5.0.12",
"brace-expansion@>=2.0.0 <3.0.0": "^2.1.7",
"brace-expansion@>=1.0.0 <2.0.0": "^1.1.21",
"form-data@>=4.0.0 <5.0.0": "^4.0.6",
"js-yaml@>=3.0.0 <4.0.0": "^3.15.2",
"js-yaml@>=4.0.0 <5.0.0": "^4.3.2",
"morgan@>=1.0.0 <2.0.0": "^1.12.1",
"@babel/core@>=7.0.0 <8.0.0": "^7.29.7",
"engine.io@>=6.0.0 <7.0.0": "^6.6.11",
"shell-quote@>=1.0.0 <2.0.0": "^1.12.0",
"body-parser@>=1.0.0 <2.0.0": "^1.20.8",
"linkify-it@>=5.0.0 <6.0.0": "^5.0.2",
"seroval@>=1.0.0 <2.0.0": "^1.6.9",
"socket.io-parser@>=4.0.0 <5.0.0": "^4.2.7",
"ip-address@>=10.0.0 <11.0.0": "^10.7.4",
"axios@>=1.0.0 <2.0.0": "^1.20.0",
"nanoid@>=5.0.0 <6.0.0": "^5.1.16",
"nanoid@>=3.0.0 <4.0.0": "^3.3.20",
"postcss-selector-parser@>=7.0.0 <8.0.0": "^7.1.6",
"browserslist@>=4.0.0 <5.0.0": "^4.29.3",
"immutable@>=5.0.0 <6.0.0": "^5.1.9",
"colord@>=2.0.0 <3.0.0": "^2.10.0",
"baseline-browser-mapping@>=2.0.0 <3.0.0": "^2.11.28",
"source-map-js@>=1.0.0 <2.0.0": "^1.2.2",
"proxy-addr@>=2.0.0 <3.0.0": "^2.0.8",
"compression@>=1.0.0 <2.0.0": "^1.8.2",
"handlebars@>=4.0.0 <5.0.0": "^4.7.10",
"websocket-driver@>=0.7.0 <0.8.0": "^0.7.5",
"@humanfs/node@>=0.16.0 <0.17.0": "^0.16.8",
"@xmldom/xmldom@>=0.8.0 <0.9.0": "^0.8.15"
},
"ignoredBuiltDependencies": [
"@parcel/watcher",
+1094 -1038
View File
File diff suppressed because it is too large. Load diff
+11 -2
View File
@@ -13,6 +13,15 @@ These overrides force specific versions of transitive dependencies, primarily fo
| `ember-try-config>package-json` | `^10.0.1` | `ember-try-config` pins an older `package-json`. | Check whether a newer `ember-try-config` release widens its `package-json` range to include v10+. |
| `ember-loading>ember-concurrency` | `^4.0.0` | `ember-loading` declares `"ember-concurrency": "^2.0.3"`. | The override and the patch (`patches/ember-loading.patch`) are a pair — the override forces v4 to be installed, the patch updates the source to use v4. Both must be removed together if `ember-loading` ever ships a version that natively supports v4. |
| `tmp` | `^0.2.7` | 10+ packages pin old versions of `tmp` (`broccoli`, `can-symlink`, `ember-cli-typescript`, `external-editor`, `fixturify-project`, `sane`, `testem`, and others) | Check whether the main Ember toolchain packages (`broccoli`, `ember-cli`, `testem`) have been updated to allow `tmp ^0.2.x`. |
| `tar` | `^7.5.10` | Both `cacache` (`^6.1.11`) and `@electron/rebuild` (`^6.0.5`) pin old ranges. | Check whether a newer `ember-electron` brings in versions of `@electron/rebuild` and `cacache` that allow `tar ^7.x`. |
| `tar` | `^7.5.22` | Both `cacache` (`^6.1.11`) and `@electron/rebuild` (`^6.0.5`) pin old ranges. | Check whether a newer `ember-electron` brings in versions of `@electron/rebuild` and `cacache` that allow `tar ^7.x`. |
| `nomnom>underscore` | `^1.13.8` | `nomnom` pins `"underscore": "~1.6.0"`. All other consumers already declare ranges that include 1.13.8. | `nomnom@1.8.1` is the last published version and the package is abandoned. `jsonlint` is the actual consumer, currently pinned to `^1.6.3` which still depends on `nomnom`. |
| `ember-cli>markdown-it` | `^14.2.0` | `ember-cli` (`~5.12.0`) pins old ranges. | Once `ember-cli` has been updated to at least `6.3.0` then this override can be removed. |
| `ember-cli>markdown-it` | `^14.3.2` | `ember-cli` (`~5.12.0`) pins old ranges. | Once `ember-cli` has been updated to at least `6.3.0` then this override can be removed. |
## Security overrides added by the Threshold fork
The overrides keyed `<name>@>=X.0.0 <Y.0.0` were generated from `pnpm audit` (see the "About this fork" section in the README). Each one only raises a transitive dependency to the latest patched release **within the same major line** (patch/minor, lockfile-only effect). They are build/test tooling dependencies (`ember-cli`, `testem`, `stylelint`, `openapi-generator`, ...), not shipped code. Remove an entry once the dependents release versions that no longer need it; re-run `pnpm audit` after removing.
Packages covered: `@babel/core`, `@humanfs/node`, `@xmldom/xmldom`, `axios`, `baseline-browser-mapping`, `body-parser`, `brace-expansion`, `browserslist`, `colord`, `compression`, `diff`, `engine.io`, `follow-redirects`, `form-data`, `handlebars`, `immutable`, `ip-address`, `js-yaml`, `linkify-it`, `morgan`, `nanoid`, `postcss`, `postcss-selector-parser`, `proxy-addr`, `qs`, `seroval`, `shell-quote`, `socket.io-parser`, `source-map-js`, `websocket-driver`, `ws`.
Known unfixed without a major bump or an upstream fix: `svgo@1` (via `ember-inline-svg`), `@faker-js/faker@8` (api addon mirage data), `uuid@8` (testem), `diff@7` (sinon), `postcss-selector-parser@6` (stylelint), `basic-ftp@5` (openapi-generator), `extract-zip@2`, `http-cache-semantics@4`, `braces@3`, `sprintf-js@1` (no patched release).
@@ -44,7 +44,7 @@
@color='secondary'
{{on 'click' @cancel}}
/>
{{#if this.grantStringsText}}
{{#if this.grantStrings.length}}
<Hds::Button
@text={{t 'actions.export'}}
@color='tertiary'
@@ -7,7 +7,9 @@ import Component from '@glimmer/component';
import { action } from '@ember/object';
import { service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { getOwner } from '@ember/application';
import {
tooltips,
autocompletion,
completionKeymap,
startCompletion,
@@ -36,7 +38,6 @@ export default class FormRoleEditGrantsComponent extends Component {
exportOptionsMap = { terraform: 'terraform', nativeHCL: 'native-hcl' };
exportOptions = Object.values(this.exportOptionsMap);
@tracked grantStringsText = (this.args.model?.grant_strings ?? []).join('\n');
@tracked currentLineText = this.args.model?.grant_strings?.[0] ?? '';
@tracked showExportOptionsFlyout = false;
@tracked selectedExportOption = this.exportOptions[0];
@@ -168,7 +169,14 @@ export default class FormRoleEditGrantsComponent extends Component {
this.translateLintingError,
);
rootElementSelector = getOwner(this).rootElement;
rootElement = getOwner(this)
.lookup('service:-document')
.querySelector(this.rootElementSelector);
customExtensions = [
// Configure tooltips to render in app root to avoid overflow issues within the editor container.
tooltips({ parent: this.rootElement }),
autocompletion({
override: [this.completionSource],
// Trigger autocompletion when the user completes a grant field (which we labeled as keywords)
@@ -179,7 +187,11 @@ export default class FormRoleEditGrantsComponent extends Component {
const line = update.state.doc.lineAt(update.state.selection.main.head);
this.currentLineText = line.text;
if (update.docChanged) {
this.grantStringsText = update.state.doc.toString();
const text = update.state.doc.toString();
this.args.model.grant_strings = text
.split('\n')
.map((s) => s.trim())
.filter(Boolean);
}
// Trigger autocomplete when we're on an empty line
if (line.text === '') {
@@ -197,11 +209,12 @@ export default class FormRoleEditGrantsComponent extends Component {
this.#editorView?.destroy();
}
get grantStringsText() {
return this.grantStrings.join('\n');
}
get grantStrings() {
return this.grantStringsText
.split('\n')
.map((grantString) => grantString.trim())
.filter(Boolean);
return this.args.model?.grant_strings ?? [];
}
/**
@@ -221,7 +234,7 @@ export default class FormRoleEditGrantsComponent extends Component {
*/
get terraformFormattedExport() {
let formatted = `grant_strings = [ \n`;
this.grantStringsText.split('\n').forEach((line) => {
this.grantStrings.forEach((line) => {
formatted += ` "${line}",\n`;
});
formatted += `]\n`;
@@ -234,7 +247,7 @@ export default class FormRoleEditGrantsComponent extends Component {
*/
get nativeHclFormattedExport() {
let formatted = `[ \n`;
this.grantStringsText.split('\n').forEach((line) => {
this.grantStrings.forEach((line) => {
formatted += ` "${line}",\n`;
});
formatted += `]\n`;
@@ -114,16 +114,16 @@ ${listenerText}
*/
get installBoundaryText() {
const configPath = this.configFilePath || '<path>';
const ossContent = `curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add - ;\\
sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" ;\\
sudo apt-get update && sudo apt-get install boundary ;\\
boundary server -config="${configPath}/pki-worker.hcl"`;
// Threshold: install the `threshold` package from your Threshold package
// repository (the package also provides a `boundary` command alias). No
// HashiCorp package or release host is referenced.
const ossContent = `sudo apt-get update && sudo apt-get install threshold ;\\
threshold server -config="${configPath}/pki-worker.hcl"`;
const hcpContent = `sudo apt-get update && sudo apt-get install jq unzip ;\\
wget -q "$(curl -fsSL "https://api.releases.hashicorp.com/v1/releases/boundary/latest?license_class=enterprise" \
| jq -r '.builds[] | select(.arch == "amd64" and .os == "linux") | .url')" ;\\
unzip *.zip ;\\
./boundary server -config="${configPath}/pki-worker.hcl"`;
// HCP-cluster workers are an HCP (HashiCorp Cloud Platform) feature; the
// generic instructions apply. Place the downloaded threshold binary in
// the working directory before running.
const hcpContent = `./threshold server -config="${configPath}/pki-worker.hcl"`;
return this.features.isEnabled('byow-pki-hcp-cluster-id')
? hcpContent
+2 -2
View File
@@ -8,8 +8,8 @@
<head>
<meta name="csp-nonce" content="__BOUNDARY_CSP_NONCE__">
<meta charset="utf-8">
<title>Admin</title>
<meta name="description" content="Simple and secure remote access with HashiCorp Boundary.">
<title>Threshold Admin</title>
<meta name="description" content="Simple and secure remote access with Threshold.">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#f24c53">
@@ -4,6 +4,7 @@
*/
import Route from '@ember/routing/route';
import { action } from '@ember/object';
import { service } from '@ember/service';
import { dropTask } from 'ember-concurrency';
import { modelMapping } from 'api/services/sqlite';
@@ -60,4 +61,15 @@ export default class ScopesScopeRolesRoleEditGrantsRoute extends Route {
return response.json();
}
/**
* Stores the role model in the transition data property so that the application level hook
* can check for dirty attributes and trigger the confirm service.
* @param {object} transition
*/
@action
async willTransition(transition) {
const { role } = transition.from.attributes;
transition.data = { model: role };
}
}
+6
View File
@@ -1042,3 +1042,9 @@
max-height: 50vh;
overflow-y: auto;
}
// Prevent grants editor tooltip from being
// hidden by code editor in fullscreen mode.
.ember-application div .cm-tooltip {
z-index: 1000;
}
@@ -11,7 +11,7 @@
<page.body>
<Rose::Frame>
<:header>
<Hds::Icon @name='boundary-color' @size='24' @isInline={{true}} />
<Hds::Icon @name='shield' @size='24' @isInline={{true}} />
<Hds::Text::Display @tag='h2' @size='400' @weight='bold'>{{t
'actions.change-password'
}}</Hds::Text::Display>
+2 -2
View File
@@ -17,8 +17,8 @@
>
<:logo>
<Hds::AppHeader::HomeLink
@icon='boundary'
@color='var(--token-color-boundary-brand)'
@icon='shield'
@color='var(--token-color-foreground-primary)'
@text={{(app-name)}}
@route='index'
class='home-link-color-override'
+1 -1
View File
@@ -6,7 +6,7 @@
<Rose::Layout::Centered>
<Rose::Frame class='create-resources'>
<:header>
<Hds::Icon @name='boundary-color' @size='24' @isInline={{true}} />
<Hds::Icon @name='shield' @size='24' @isInline={{true}} />
<Hds::Text::Display @tag='h2' @size='400' @weight='bold'>{{t
'onboarding.add-target.titles.have-a-target'
}}</Hds::Text::Display>
@@ -8,7 +8,7 @@
<Rose::Layout::Centered>
<Rose::Frame class='create-resources'>
<:header>
<Hds::Icon @name='boundary-color' @size='24' @isInline={{true}} />
<Hds::Icon @name='shield' @size='24' @isInline={{true}} />
<Hds::Text::Display @tag='h2' @size='400' @weight='bold'>{{t
'onboarding.success.titles.connect'
}}</Hds::Text::Display>
@@ -15,7 +15,7 @@
{{else}}
<Rose::Frame>
<:header>
<Hds::Icon @name='boundary-color' @size='24' @isInline={{true}} />
<Hds::Icon @name='shield' @size='24' @isInline={{true}} />
<Hds::Text::Display @tag='h2' @size='400' @weight='bold'>{{t
'actions.authenticate'
}}</Hds::Text::Display>
+2 -2
View File
@@ -617,7 +617,7 @@ const validateActionsField = (
diagnostics.push({
from: pos.valueStart,
to: pos.valueEnd,
severity: 'error',
severity: 'warning',
message: translate('actions.noop-requires-list'),
});
return;
@@ -637,7 +637,7 @@ const validateActionsField = (
diagnostics.push({
from: pos.valueStart,
to: pos.valueEnd,
severity: 'error',
severity: 'warning',
message: translate('actions.list-requires-noop'),
actions: [createAddTextAction(translate('editor.add-noop'))],
});
+4 -3
View File
@@ -12,7 +12,7 @@ const {
licensedFeatures,
} = require('./features');
const APP_NAME = process.env.APP_NAME || 'Boundary';
const APP_NAME = process.env.APP_NAME || 'Threshold';
const API_HOST = process.env.API_HOST || '';
const ENABLE_A11Y_AUDIT = process.env.ENABLE_A11Y_AUDIT || false;
const COLOR_THEME = process.env.COLOR_THEME ?? 'light';
@@ -52,7 +52,7 @@ module.exports = function (environment) {
},
appName: APP_NAME,
companyName: 'HashiCorp',
companyName: 'CyberCove LLC',
oidcPollingTimeoutSeconds: 1,
@@ -147,7 +147,8 @@ module.exports = function (environment) {
alias: '/docs/concepts/aliases',
'alias.single-word-aliases':
'/docs/targets/configuration#single-word-aliases-and-transparent-sessions',
'support-page': 'https://support.hashicorp.com/hc/en-us',
'support-page':
'https://repo.anhonesthost.net/CyberCoveLLC/threshold-ui/issues',
},
},
+2 -2
View File
@@ -2,9 +2,9 @@
"name": "admin",
"version": "0.0.0",
"private": true,
"description": "Admin UI for Boundary.",
"description": "Admin UI for Threshold.",
"license": "BUSL-1.1",
"author": "HashiCorp",
"author": "CyberCove LLC (fork of HashiCorp Boundary UI)",
"directories": {
"doc": "doc",
"test": "tests"
@@ -460,4 +460,58 @@ module('Acceptance | credential-libraries | update', function (hooks) {
selectors.FIELD_VAULT_PATH_VALUE,
);
});
test('can update a vault generic credential library without credential_type and save changes without error', async function (assert) {
setRunOptions({
rules: {
'color-contrast': {
// [ember-a11y-ignore]: axe rule "color-contrast" automatically ignored on 2026-07-07
enabled: false,
},
},
});
const credentialLibraryWithoutType = this.server.create(
'credential-library',
{
scope: instances.scopes.project,
credentialStore: instances.credentialStore,
type: TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
credential_type: null,
credentialMappingOverrides: null,
},
);
await visit(
`${urls.credentialLibraries}/${credentialLibraryWithoutType.id}`,
);
await click(commonSelectors.EDIT_BTN, 'Activate edit mode');
await fillIn(commonSelectors.FIELD_NAME, commonSelectors.FIELD_NAME_VALUE);
await fillIn(
commonSelectors.FIELD_DESCRIPTION,
commonSelectors.FIELD_DESCRIPTION_VALUE,
);
await fillIn(selectors.FIELD_VAULT_PATH, selectors.FIELD_VAULT_PATH_VALUE);
await click(commonSelectors.SAVE_BTN);
const credentialLibrary = this.server.schema.credentialLibraries.find(
credentialLibraryWithoutType.id,
);
assert.strictEqual(
credentialLibrary.name,
commonSelectors.FIELD_NAME_VALUE,
);
assert.strictEqual(
credentialLibrary.description,
commonSelectors.FIELD_DESCRIPTION_VALUE,
);
assert.strictEqual(
credentialLibrary.attributes.path,
selectors.FIELD_VAULT_PATH_VALUE,
);
assert.strictEqual(credentialLibrary.credentialType, null);
});
});
@@ -348,4 +348,83 @@ module('Acceptance | roles/edit grants', function (hooks) {
assert.dom(selectors.AUTOCOMPLETE_TOOLTIP).isVisible();
});
test('can discard unsaved grant changes via dialog', async function (assert) {
setRunOptions({
rules: {
'color-contrast': {
// [ember-a11y-ignore]: axe rule "color-contrast" automatically ignored on 2026-06-17
enabled: false,
},
},
});
assert.expect(3);
const confirmService = this.owner.lookup('service:confirm');
confirmService.enabled = true;
await visit(urls.editGrants);
await waitFor(commonSelectors.CODE_EDITOR_CM);
const newGrantString = 'ids=*;type=session;actions=list';
const editorElement = find(commonSelectors.CODE_EDITOR_CODE);
const editorView = editorElement.editor;
editorView.dispatch({
changes: {
from: editorView.state.doc.length,
insert: `\n${newGrantString}`,
},
});
await click(commonSelectors.HREF(urls.role));
assert.dom(commonSelectors.MODAL_WARNING).isVisible();
await click(commonSelectors.MODAL_WARNING_CONFIRM_BTN);
assert.strictEqual(currentURL(), urls.role);
console.log(this.server.schema.roles.find(instances.role.id));
assert.false(
this.server.schema.roles
.find(instances.role.id)
.grant_strings.includes(newGrantString),
);
});
test('can cancel discard grant changes via dialog', async function (assert) {
setRunOptions({
rules: {
'color-contrast': {
// [ember-a11y-ignore]: axe rule "color-contrast" automatically ignored on 2026-06-17
enabled: false,
},
},
});
assert.expect(3);
const confirmService = this.owner.lookup('service:confirm');
confirmService.enabled = true;
await visit(urls.editGrants);
await waitFor(commonSelectors.CODE_EDITOR_CM);
const newGrantString = 'ids=*;type=session;actions=list';
const editorElement = find(commonSelectors.CODE_EDITOR_CODE);
const editorView = editorElement.editor;
editorView.dispatch({
changes: {
from: editorView.state.doc.length,
insert: `\n${newGrantString}`,
},
});
await click(commonSelectors.HREF(urls.role));
assert.dom(commonSelectors.MODAL_WARNING).isVisible();
await click(commonSelectors.MODAL_WARNING_CANCEL_BTN);
assert.strictEqual(currentURL(), urls.editGrants);
assert
.dom(commonSelectors.CODE_EDITOR_CONTENT)
.includesText(newGrantString);
});
});
@@ -76,7 +76,7 @@ module('Acceptance | workers | create', function (hooks) {
const labels = findAll(selectors.WORKER_CREATE_SECTION_FORM_LABEL);
assert.dom(labels[0]).hasText('Boundary Cluster ID (Optional)');
assert.dom(labels[0]).hasText('Threshold Cluster ID (Optional)');
assert.dom(labels[2]).doesNotIncludeText('Initial Upstreams');
});
@@ -100,7 +100,7 @@ module('Acceptance | workers | create', function (hooks) {
const labels = findAll(selectors.WORKER_CREATE_SECTION_FORM_LABEL);
assert.false(featuresService.isEnabled('byow-pki-hcp-cluster-id'));
assert.dom(labels[0]).doesNotIncludeText('Boundary Cluster ID');
assert.dom(labels[0]).doesNotIncludeText('Threshold Cluster ID');
assert.dom(labels[2]).hasText('Initial Upstreams (Optional)');
});
@@ -126,14 +126,10 @@ module('Acceptance | workers | create', function (hooks) {
assert.false(featuresService.isEnabled('byow-pki-hcp-cluster-id'));
assert
.dom(createSection[1])
.includesText(
'curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add - ;',
);
.includesText('sudo apt-get install threshold ;');
assert
.dom(createSection[1])
.doesNotIncludeText(
'wget -q "$(curl -fsSL "https://api.releases.hashicorp.com/v1/releases/boundary/latest?license_class=enterprise"',
);
.doesNotIncludeText('./threshold server -config=');
});
test('download and install step shows correct hcp instructions', async function (assert) {
@@ -156,16 +152,10 @@ module('Acceptance | workers | create', function (hooks) {
const createSection = findAll(selectors.WORKER_CREATE_SECTION);
assert.dom(createSection[1]).includesText('./threshold server -config=');
assert
.dom(createSection[1])
.includesText(
'wget -q "$(curl -fsSL "https://api.releases.hashicorp.com/v1/releases/boundary/latest?license_class=enterprise"',
);
assert
.dom(createSection[1])
.doesNotIncludeText(
'curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add - ;',
);
.doesNotIncludeText('sudo apt-get install threshold ;');
});
test('Users can navigate to new workers route with proper authorization', async function (assert) {
+7
View File
@@ -2,6 +2,13 @@
Canonical reference for changes, improvements, and bugfixes for Boundary Desktop.
## v2.6.2 [CLI 0.21.3] (2026.07.10)
### New & Improved
- Upgrade CLI to v0.21.3 ([PR](https://github.com/hashicorp/boundary-ui/pull/3336))
## V2.6.1 [CLI 0.21.2] (2026.06.30)
### Bug Fixes
@@ -3,7 +3,7 @@
SPDX-License-Identifier: BUSL-1.1
}}
<SettingsCard @header={{t 'settings.application'}} @icon='boundary'>
<SettingsCard @header={{t 'settings.application'}} @icon='shield'>
<:body>
<div>
<Hds::Text::Display>
+8 -2
View File
@@ -6,6 +6,7 @@
import Route from '@ember/routing/route';
import { service } from '@ember/service';
import { TrackedArray } from 'tracked-built-ins';
import config from 'desktop/config/environment';
export default class ScopesRoute extends Route {
// =services
@@ -62,12 +63,16 @@ export default class ScopesRoute extends Route {
let downloadError = false;
if (!this.isPaginationSupported) {
const metaDataUrl =
'https://api.releases.hashicorp.com/v1/releases/boundary-desktop/1.7.1';
// Threshold has no default release metadata API (the upstream
// HashiCorp releases API is intentionally not contacted). When
// `config.releases.metadataUrl` is empty we skip the request and direct
// the user to the releases page instead.
const metaDataUrl = config.releases?.metadataUrl;
const { isWindows, isMac, isLinux } =
await window.desktop.system.checkOS();
try {
if (!metaDataUrl) throw new Error('No release metadata URL');
const metaDataResponse = await fetch(metaDataUrl);
const metaData = await metaDataResponse.json();
@@ -87,6 +92,7 @@ export default class ScopesRoute extends Route {
}
}
controller.set('releasesPageUrl', config.releases?.releasesPageUrl);
controller.set('downloadLink', downloadLink);
controller.set('downloadError', downloadError);
}
+2 -2
View File
@@ -15,8 +15,8 @@
>
<:logo>
<Hds::AppHeader::HomeLink
@icon='boundary'
@color='var(--token-color-boundary-brand)'
@icon='shield'
@color='var(--token-color-foreground-primary)'
@text={{(app-name)}}
@route='index'
class='app-header__logo home-link-color-override'
+1 -1
View File
@@ -26,7 +26,7 @@
<A.Button
@text={{t 'unsupported-controller.buttons.releases-page'}}
@color='secondary'
@href='https://releases.hashicorp.com/boundary-desktop/'
@href={{this.releasesPageUrl}}
@isHrefExternal={{true}}
data-test-releases-link
/>
+17 -2
View File
@@ -5,7 +5,7 @@
'use strict';
const APP_NAME = process.env.APP_NAME || 'Boundary';
const APP_NAME = process.env.APP_NAME || 'Threshold';
const locationType = process.env.EMBER_CLI_ELECTRON ? 'hash' : 'history';
const ENABLE_A11Y_AUDIT = process.env.ENABLE_A11Y_AUDIT || false;
const COLOR_THEME = process.env.COLOR_THEME ?? 'light';
@@ -41,6 +41,16 @@ module.exports = function (environment) {
appName: APP_NAME,
// Threshold has no default release metadata API; set `metadataUrl` to a
// HashiCorp-releases-API-compatible endpoint to enable direct download links
// when connecting to an older controller. See README "About this fork".
releases: {
metadataUrl: process.env.THRESHOLD_RELEASES_METADATA_URL || '',
releasesPageUrl:
process.env.THRESHOLD_RELEASES_PAGE_URL ||
'https://repo.anhonesthost.net/CyberCoveLLC/threshold-ui/releases',
},
oidcPollingTimeoutSeconds: 1,
sessionPollingTimeoutSeconds: 2,
@@ -51,7 +61,8 @@ module.exports = function (environment) {
'/tutorials/oss-getting-started/oss-getting-started-desktop-app#connect',
sessions:
'/tutorials/oss-getting-started/oss-getting-started-desktop-app#connect',
'support-page': 'https://support.hashicorp.com/hc/en-us',
'support-page':
'https://repo.anhonesthost.net/CyberCoveLLC/threshold-ui/issues',
},
},
@@ -104,6 +115,10 @@ module.exports = function (environment) {
ENV.enableConfirmService = false;
// Use a non-routable host for mocked release metadata.
ENV.releases.metadataUrl = 'https://releases-api.threshold.invalid/v1/meta';
ENV.releases.releasesPageUrl = 'https://releases.threshold.invalid/';
// Use in-memory storage
ENV.storage = {
memory: true,
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 334 B

Binary file not shown.
+17 -3
View File
@@ -39,10 +39,24 @@ const downloadArtifact = (version) => {
`Download cli for platform: ${archivePlatform.name} arch: ${archivePlatform.arch}`,
);
const archiveName = `boundary_${version}_${archivePlatform.name}_${archivePlatform.arch}.zip`;
const url = `https://releases.hashicorp.com/boundary/${version}/${archiveName}`;
// Threshold does not default to any download host. The CLI release base URL
// must be provided (layout: `<base>/<version>/<prefix>_<version>_<os>_<arch>.zip`).
const baseUrl = (process.env.THRESHOLD_CLI_RELEASES_URL || '').replace(
/\/+$/,
'',
);
if (!baseUrl) {
throw new Error(
'THRESHOLD_CLI_RELEASES_URL must be set when SETUP_CLI=true (no default download host is configured).',
);
}
const archivePrefix = process.env.THRESHOLD_CLI_ARCHIVE_PREFIX || 'threshold';
const archiveName = `${archivePrefix}_${version}_${archivePlatform.name}_${archivePlatform.arch}.zip`;
const url = `${baseUrl}/${version}/${archiveName}`;
return new Promise((resolve, reject) => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'boundary-artifact-'));
const tmpDir = fs.mkdtempSync(
path.join(os.tmpdir(), 'threshold-artifact-'),
);
console.log('Create tmp artifact directory: ', tmpDir);
const artifactFileName = url.split('/').pop();
+1 -1
View File
@@ -1 +1 @@
0.21.2
0.21.3
+9 -5
View File
@@ -19,12 +19,16 @@ const returnSemVerFromReleaseVersion = (releaseVersion) => {
// Create config
const createConfig = () => {
const config = {
name: 'boundary',
productName: 'Boundary',
copyright: `Copyright © ${new Date().getFullYear()} HashiCorp, Inc.`,
name: 'threshold',
productName: 'Threshold',
// Upstream copyright is retained; see NOTICE and LICENSE in the repository root.
copyright: `Copyright © 2021-2026 HashiCorp, Inc. / IBM Corp. (upstream Boundary UI, BUSL-1.1). Threshold fork by CyberCove LLC.`,
releaseVersion: process.env.RELEASE_VERSION,
releaseCommit: process.env.RELEASE_COMMIT,
executableName: 'Boundary',
executableName: 'Threshold',
// Update feed (directory listing in the releases.hashicorp.com layout).
// Empty disables the in-app updater and the update-related network access.
updateFeedUrl: process.env.THRESHOLD_UPDATE_FEED_URL || '',
releaseVersionRaw: process.env.RELEASE_VERSION,
};
@@ -38,7 +42,7 @@ const createConfig = () => {
);
}
if (isLinux()) config.executableName = 'boundary-desktop';
if (isLinux()) config.executableName = 'threshold-desktop';
return config;
};
+14 -9
View File
@@ -1,6 +1,11 @@
// Generated during build
const config = require('./config.js');
const { isMac } = require('../src/helpers/platform.js');
// THRESHOLD_* is preferred; the upstream BOUNDARY_* name remains supported.
const signingIdentity =
process.env.THRESHOLD_DESKTOP_SIGNING_IDENTITY ||
process.env.BOUNDARY_DESKTOP_SIGNING_IDENTITY;
const fs = require('fs');
const path = require('path');
@@ -17,11 +22,11 @@ module.exports = {
icon: './assets/app-icons/icon',
name: config.productName,
appVersion: config.releaseVersion,
appBundleId: 'com.electron.boundary',
appBundleId: 'net.anhonesthost.cybercove.threshold',
appCopyright: config.copyright,
executableName: config.executableName,
osxSign: {
identity: process.env.BOUNDARY_DESKTOP_SIGNING_IDENTITY,
identity: signingIdentity,
'hardened-runtime': true,
entitlements: './assets/macos/entitlements.plist',
'entitlements-inherit': './assets/macos/entitlements.plist',
@@ -39,7 +44,7 @@ module.exports = {
},
beforeAsar: [
async (buildPath, electronVersion, platform, arch, done) => {
// Delete the boundary CLI before we build the ASAR as it gets copied outside
// Delete the bundled CLI before we build the ASAR as it gets copied outside
// in the resources folder
const cliPath = path.join(buildPath, 'cli');
await fs.promises.rm(cliPath, { recursive: true, force: true });
@@ -68,11 +73,11 @@ module.exports = {
name: '@electron-forge/maker-deb',
config: {
options: {
name: 'boundary-desktop',
name: 'threshold-desktop',
version: config.releaseVersion,
icon: './assets/app-icons/icon.png',
description: 'Desktop Client for Boundary',
productDescription: 'Desktop Client for Boundary',
description: 'Desktop Client for Threshold',
productDescription: 'Desktop Client for Threshold',
},
},
},
@@ -83,7 +88,7 @@ module.exports = {
console.log(`[package] Release version: ${config.releaseVersion}`);
// Check for MacOS signing identity.
if (isMac() && !process.env.BOUNDARY_DESKTOP_SIGNING_IDENTITY)
if (isMac() && !signingIdentity)
console.warn(
'[package] WARNING: Could not find signing identity. Proceeding without signing.',
);
@@ -116,11 +121,11 @@ module.exports = {
}
if (platform === 'linux' && artifact.endsWith('.deb')) {
name = `boundary-desktop_${version}_${arch}${path.extname(
name = `threshold-desktop_${version}_${arch}${path.extname(
artifact,
)}`;
} else {
name = `boundary-desktop_${version}_${platform}_${arch}${path.extname(
name = `threshold-desktop_${version}_${platform}_${arch}${path.extname(
artifact,
)}`;
}
+5 -5
View File
@@ -1,11 +1,11 @@
{
"name": "boundary-desktop",
"productName": "Boundary",
"name": "threshold-desktop",
"productName": "Threshold",
"version": "0.0.0",
"private": true,
"description": "Electron UI for client for Boundary.",
"description": "Electron desktop client for Threshold.",
"license": "BUSL-1.1",
"author": "HashiCorp",
"author": "CyberCove LLC (fork of HashiCorp Boundary UI)",
"main": "src/index.js",
"scripts": {
"build:cli": "node -e \"require('./config/cli.js').setup()\"",
@@ -44,7 +44,7 @@
"@electron-forge/maker-dmg": "^7.11.0",
"@electron-forge/maker-squirrel": "^7.11.0",
"@electron-forge/maker-zip": "^7.11.0",
"electron": "42.0.1",
"electron": "42.11.12",
"esbuild": "^0.25.4",
"unzipper": "^0.11.5"
},
+458 -466
View File
File diff suppressed because it is too large. Load diff
+3 -3
View File
@@ -4,11 +4,11 @@
*/
const { spawnSync } = require('../helpers/spawn-promise.js');
const { path, isBuiltInCli } = require('./path.js');
const { resolveCliPath, isBuiltInCli } = require('./path.js');
module.exports = {
// Check boundary cli existence
exists: () => Boolean(path),
// Check threshold (or boundary) cli existence
exists: () => Boolean(resolveCliPath()),
isBuiltInCli,
+46 -19
View File
@@ -9,31 +9,58 @@ const isDev = require('electron-is-dev');
const { existsSync } = require('node:fs');
const which = require('which');
const binaryName = isWindows() ? 'boundary.exe' : 'boundary';
const builtInCliPath = isDev
? path.resolve(__dirname, '..', '..', 'cli', binaryName)
: path.resolve(process.resourcesPath, 'cli', binaryName);
// Candidate CLI binary names, in order of preference. Threshold ships a
// `threshold` binary; the server package also ships a `boundary` alias, and
// upstream Boundary installs are still supported.
const cliNames = ['threshold', 'boundary'];
const exe = (name) => (isWindows() ? `${name}.exe` : name);
const builtInDir = isDev
? path.resolve(__dirname, '..', '..', 'cli')
: path.resolve(process.resourcesPath, 'cli');
// Built-in CLI (bundled in the app resources), first match wins.
const builtInCliPath = cliNames
.map((name) => path.resolve(builtInDir, exe(name)))
.find((candidate) => existsSync(candidate));
// Return true if the CLI in usage is the built in. False if relies on system CLI.
const isBuiltInCli = existsSync(builtInCliPath);
const isBuiltInCli = Boolean(builtInCliPath);
let cachedSystemCli;
/**
* Returns Boundary CLI path if the CLI is built in or the Boundary binary name
* if not, so we assume boundary is available within user $PATH.
* Looks up the first available CLI name in the user's $PATH. On Windows we
* also filter out any path within the current working directory because spawn
* methods may not always find the correct binary path.
* Resolved lazily (the app fixes up $PATH after this module is first loaded)
* and cached once found. Falls back to the preferred name so spawn errors are
* meaningful.
*/
const pathBoundary = isBuiltInCli
? builtInCliPath
: // On Windows, we need to filter out the path that is within the current working directory.
// This is necessary because the spawn methods may not always find the correct binary path.
// The `which` module returns an array of all available paths for the 'boundary' binary.
// We then filter out the path that is within the current working directory.
isWindows()
? which
.sync(binaryName, { nothrow: true, all: true })
.filter((binary) => !binary.startsWith(process.cwd()))[0]
: binaryName;
const findSystemCli = () => {
if (cachedSystemCli) return cachedSystemCli;
for (const name of cliNames) {
const found = which
.sync(exe(name), { nothrow: true, all: true })
?.filter((binary) => !isWindows() || !binary.startsWith(process.cwd()));
if (found && found.length) {
cachedSystemCli = isWindows() ? found[0] : exe(name);
return cachedSystemCli;
}
}
return isWindows() ? undefined : exe(cliNames[0]);
};
/**
* Returns the CLI path if the CLI is built in, otherwise the name (or path)
* of the first of `threshold` / `boundary` found within user $PATH.
*/
const resolveCliPath = () => (isBuiltInCli ? builtInCliPath : findSystemCli());
module.exports = {
path: pathBoundary,
resolveCliPath,
get path() {
return resolveCliPath();
},
isBuiltInCli,
};
@@ -5,6 +5,7 @@
const runtimeSettings = require('../services/runtime-settings.js');
const isDev = require('electron-is-dev');
const appUpdater = require('../helpers/app-updater.js');
const csp = {
'default-src': ["'none'"],
@@ -39,9 +40,13 @@ const generateCSPHeader = () => {
policy['connect-src'].push(runtimeSettings.clusterUrl);
}
// add hashicorp release endpoints to connect-src
policy['connect-src'].push('https://api.releases.hashicorp.com');
policy['connect-src'].push('https://releases.hashicorp.com');
// Allow the configured update feed origin (if any) in connect-src. There is
// no default feed; the in-app updater is disabled unless one is configured.
const updateFeedOrigin = appUpdater.feedOrigin();
if (updateFeedOrigin) {
policy['connect-src'] = policy['connect-src'].slice();
policy['connect-src'].push(updateFeedOrigin);
}
return Object.keys(policy)
.map((key) => `${key} ${policy[key].join(' ')};`)
+6 -3
View File
@@ -23,14 +23,14 @@ const generateMenuTemplate = () => {
...(isMac()
? [
{
label: 'Boundary',
label: 'Threshold',
submenu: [
// { role: 'about' },
{
label: `About ${config.productName}`,
click: aboutDialog,
},
...(isBuiltInCli
...(isBuiltInCli && appUpdater.isEnabled()
? [
{
id: 'update',
@@ -115,7 +115,10 @@ const generateMenuTemplate = () => {
submenu: [
{
label: 'Documentation',
click: () => shell.openExternal('https://www.boundaryproject.io'),
click: () =>
shell.openExternal(
'https://repo.anhonesthost.net/CyberCoveLLC/threshold-ui',
),
},
...(isWindows()
? [
@@ -16,7 +16,23 @@ const boundaryCli = require('../cli/index.js');
const currentVersion = config.releaseVersion;
const debug = process.env.DEBUG_APP_UPDATER;
const releasesUrl = 'https://releases.hashicorp.com/boundary-desktop/';
// Threshold has no default update feed. The updater is only active when a feed
// URL is configured at build time (THRESHOLD_UPDATE_FEED_URL, see
// config/desktop.js). The feed is expected to be a directory listing that
// follows the upstream releases layout (`<feed>/<version>/threshold-desktop_<version>_darwin_<arch>.zip`).
const feedUrl = (config.updateFeedUrl || '').trim();
const releasesUrl = feedUrl ? feedUrl.replace(/\/?$/, '/') : '';
const isEnabled = () => Boolean(releasesUrl);
// Origin of the feed for use in the content security policy.
const feedOrigin = () => {
try {
return releasesUrl ? new URL(releasesUrl).origin : '';
} catch {
return '';
}
};
// Returns the real CPU architecture of the machine.
const returnArchitectureToUpdate = () => {
@@ -56,7 +72,7 @@ const findLatestVersion = (url) => {
// Find zip archive for update
const findUpdateArchive = (version) => {
const architecture = returnArchitectureToUpdate();
const url = `${releasesUrl}${version}/boundary-desktop_${version}_darwin_${architecture}.zip`;
const url = `${releasesUrl}${version}/threshold-desktop_${version}_darwin_${architecture}.zip`;
return new Promise((resolve, reject) => {
https.get(url, (response) => {
if (response.statusCode === 200) {
@@ -156,12 +172,19 @@ const displayDownloadPrompt = (latestVersion, url) => {
* TODO: download progress in dialog
**/
module.exports = {
isEnabled,
feedOrigin,
run: async ({ suppressNoUpdatePrompt } = {}) => {
/**
* Ignore app updater prompts.
*/
if (process.env.BYPASS_APP_UPDATER) return;
/**
* No update feed configured: never contact any server.
*/
if (!isEnabled()) return;
/**
* Disable app updater check for linux as update is unsupported.
* TODO: Enable for windows pending feature dev. Windows is supported.
@@ -0,0 +1,52 @@
/**
* Threshold fork: the application name changed from "Boundary" to "Threshold",
* which changes Electron's default `userData` directory. To avoid losing a
* user's persisted settings (cluster URL, log level, preferred RDP client,
* stored session partition) we copy the legacy directory once, the first time
* the new directory does not exist yet. The legacy directory is left untouched.
*
* This must run before any module that instantiates `electron-store`.
*/
const fs = require('fs');
const path = require('path');
const { app } = require('electron');
const LEGACY_APP_NAMES = ['Boundary'];
// Minimal recursive copy (regular files and directories only).
const copyDir = (source, destination) => {
fs.mkdirSync(destination, { recursive: true });
for (const entry of fs.readdirSync(source, { withFileTypes: true })) {
const from = path.join(source, entry.name);
const to = path.join(destination, entry.name);
if (entry.isDirectory()) copyDir(from, to);
else if (entry.isFile()) fs.copyFileSync(from, to);
}
};
const migrate = () => {
try {
const userData = app.getPath('userData');
if (fs.existsSync(userData)) return;
const appData = path.dirname(userData);
for (const legacyName of LEGACY_APP_NAMES) {
const legacyDir = path.join(appData, legacyName);
if (
legacyDir !== userData &&
fs.existsSync(path.join(legacyDir, 'config.json'))
) {
copyDir(legacyDir, userData);
return;
}
}
} catch (e) {
// Never block startup because of a failed best-effort migration.
console.warn('Could not migrate legacy user data:', e.message);
}
};
migrate();
module.exports = { migrate };
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: BUSL-1.1
*/
const { path: boundaryPath } = require('../cli/path.js');
const { resolveCliPath } = require('../cli/path.js');
const { spawn, spawnSync } = require('child_process');
// You can throw exceptions, or allow them to occur, and this is supported.
@@ -28,7 +28,7 @@ module.exports = {
* @param {object} envVars
* @param {string} path
* @returns {{stdout: string | undefined, stderr: string | undefined}} */
spawnSync(args, envVars = {}, path = boundaryPath) {
spawnSync(args, envVars = {}, path = resolveCliPath()) {
const childProcess = spawnSync(path, args, {
// Some of our outputs (namely cache daemon searching) can be very large.
// This an undocumented hack to allow for an unlimited buffer size which
@@ -54,7 +54,7 @@ module.exports = {
* @param options
* @param path
*/
spawn(command, options = {}, path = boundaryPath) {
spawn(command, options = {}, path = resolveCliPath()) {
const { onClose, ...spawnOptions } = options;
return new Promise((resolve, reject) => {
const childProcess = spawn(path, command, spawnOptions);
+9 -8
View File
@@ -14,6 +14,8 @@ const {
MenuItem,
shell,
} = require('electron');
// Must be first: copies legacy "Boundary" settings before electron-store loads.
require('./helpers/legacy-user-data.js');
require('./ipc/handlers.js');
const log = require('electron-log/main');
@@ -68,11 +70,11 @@ log.transports.file.maxSize = 10485760;
// Immediately log the version information
log.info(
`Boundary Desktop Client Version: ${config.releaseVersion} | Commit: ${config.releaseCommit}`,
`Threshold Desktop Client Version: ${config.releaseVersion} | Commit: ${config.releaseCommit}`,
);
const cliInfo = version();
log.info(
`Boundary CLI Version: ${cliInfo.versionNumber} | Commit: ${cliInfo.gitRevision}`,
`Threshold CLI Version: ${cliInfo.versionNumber} | Commit: ${cliInfo.gitRevision}`,
);
if (isWindows()) {
@@ -158,17 +160,16 @@ const createWindow = async (partition, closeWindowCB) => {
});
// Opens external links in the host default browser.
// We allow developer.hashicorp.com domain to open on an external window
// and releases.hashicorp.com domain to download the desktop app or
// link to the release page for the desktop app or
// We allow the upstream Boundary documentation (developer.hashicorp.com,
// user-initiated link clicks only) and this fork's project pages to open on
// an external window, or
// apps.apple.com domain to open the app store page to download the Windows App or
// learn.microsoft.com domain to open the documentation for installing Remote Desktop Connection.
browserWindow.webContents.setWindowOpenHandler(({ url }) => {
if (
isLocalhost(url) ||
url.startsWith('https://developer.hashicorp.com/') ||
url.startsWith('https://releases.hashicorp.com/boundary-desktop/') ||
url.startsWith('https://support.hashicorp.com/hc/en-us') ||
url.startsWith('https://repo.anhonesthost.net/CyberCoveLLC/') ||
url.startsWith('https://learn.microsoft.com/') ||
url.startsWith('https://apps.apple.com/')
) {
@@ -282,7 +283,7 @@ app.on('ready', async () => {
/**
* Need for Mac OS behavior of closing the window but not the app.
* This allows a user to reopen the window when clicking the Boundary icon in the dock,
* This allows a user to reopen the window when clicking the Threshold icon in the dock,
* only when the app has not been closed.
* More info: https://www.electronjs.org/docs/latest/tutorial/quick-start#open-a-window-if-none-are-open-macos
*/
+3 -3
View File
@@ -261,11 +261,11 @@ handle('getLogPath', () => {
case 'win32':
return `${
process.env.USERPROFILE ?? '%USERPROFILE%'
}\\AppData\\Roaming\\Boundary\\logs\\desktop-client.log`;
}\\AppData\\Roaming\\Threshold\\logs\\desktop-client.log`;
case 'darwin':
return '~/Library/Logs/Boundary/desktop-client.log';
return '~/Library/Logs/Threshold/desktop-client.log';
case 'linux':
return '~/.config/Boundary/logs/desktop-client.log';
return '~/.config/Threshold/logs/desktop-client.log';
}
});
+2 -2
View File
@@ -2,9 +2,9 @@
"name": "desktop",
"version": "0.0.0",
"private": true,
"description": "Client UI for Boundary.",
"description": "Client UI for Threshold.",
"license": "BUSL-1.1",
"author": "HashiCorp",
"author": "CyberCove LLC (fork of HashiCorp Boundary UI)",
"directories": {
"doc": "doc",
"test": "tests"
+1 -72
View File
@@ -1,72 +1 @@
<svg width="247" height="78" viewBox="0 0 247 78" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="247" height="78">
<rect width="247" height="78" fill="#C4C4C4"/>
</mask>
<g mask="url(#mask0)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.164856 -1.62486C-0.0422516 -1.26614 0.0806732 -0.807445 0.439392 -0.600347L143.553 82.0216C143.911 82.2287 144.37 82.1058 144.577 81.7471C144.784 81.3884 144.661 80.9297 144.303 80.7226L1.18936 -1.8994C0.830643 -2.1065 0.371948 -1.98358 0.164856 -1.62486Z" fill="url(#paint0_linear)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.074 -1.62492C15.8669 -1.26621 15.9898 -0.807512 16.3485 -0.600381L151.489 77.4354C151.848 77.6425 152.307 77.5197 152.514 77.161C152.721 76.8023 152.598 76.3436 152.24 76.1364L17.0986 -1.89937C16.7398 -2.1065 16.2811 -1.98362 16.074 -1.62492Z" fill="url(#paint1_linear)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M31.9481 -1.62477C31.7411 -1.26602 31.8641 -0.807346 32.2228 -0.600296L159.427 72.814C159.785 73.0211 160.244 72.8981 160.451 72.5393C160.658 72.1806 160.535 71.7219 160.177 71.5149L32.9726 -1.89945C32.6138 -2.1065 32.1552 -1.98352 31.9481 -1.62477Z" fill="url(#paint2_linear)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M47.8574 -1.62475C47.6504 -1.26599 47.7734 -0.807321 48.1321 -0.600283L167.399 68.2279C167.758 68.4349 168.216 68.3119 168.424 67.9531C168.631 67.5944 168.508 67.1357 168.149 66.9287L48.8819 -1.89947C48.5231 -2.1065 48.0644 -1.98351 47.8574 -1.62475Z" fill="url(#paint3_linear)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M63.7667 -1.62481C63.5596 -1.26607 63.6825 -0.807393 64.0413 -0.60032L175.336 63.6416C175.695 63.8487 176.153 63.7257 176.36 63.367C176.567 63.0083 176.444 62.5496 176.086 62.3425L64.7912 -1.89943C64.4324 -2.1065 63.9737 -1.98355 63.7667 -1.62481Z" fill="url(#paint4_linear)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M84.6327 0.695792C84.4256 1.05451 84.5484 1.5132 84.9072 1.72032L188.229 61.3761C188.588 61.5832 189.047 61.4603 189.254 61.1016C189.461 60.7429 189.338 60.2842 188.98 60.077L85.6572 0.421292C85.2985 0.214178 84.8398 0.337076 84.6327 0.695792Z" fill="url(#paint5_linear)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M159.152 -1.62479C158.945 -1.26604 159.068 -0.807367 159.427 -0.600307L231.001 40.7107C231.36 40.9177 231.818 40.7948 232.025 40.436C232.232 40.0773 232.11 39.6186 231.751 39.4116L160.177 -1.89944C159.818 -2.1065 159.359 -1.98354 159.152 -1.62479ZM143.278 -1.62493C143.071 -1.26623 143.194 -0.807523 143.552 -0.600387L215.091 40.7106C215.45 40.9177 215.909 40.7949 216.116 40.4362C216.323 40.0775 216.2 39.6188 215.842 39.4116L144.303 -1.89936C143.944 -2.1065 143.485 -1.98363 143.278 -1.62493Z" fill="#F04E54"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M175.061 -1.62493C174.854 -1.26623 174.977 -0.807524 175.336 -0.600387L246.875 40.7106C247.234 40.9177 247.692 40.7949 247.899 40.4362C248.106 40.0775 247.984 39.6188 247.625 39.4116L176.086 -1.89936C175.727 -2.1065 175.269 -1.98363 175.061 -1.62493Z" fill="#F04E54"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M232.025 39.6862C231.818 39.3274 231.36 39.2045 231.001 39.4115L159.427 80.7225C159.068 80.9296 158.945 81.3883 159.152 81.747C159.359 82.1058 159.818 82.2287 160.177 82.0217L231.751 40.7107C232.11 40.5036 232.232 40.0449 232.025 39.6862Z" fill="url(#paint6_linear)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M216.116 39.686C215.909 39.3273 215.45 39.2045 215.091 39.4116L143.553 80.7226C143.194 80.9297 143.071 81.3884 143.278 81.7471C143.485 82.1059 143.944 82.2287 144.303 82.0216L215.842 40.7106C216.2 40.5035 216.323 40.0447 216.116 39.686Z" fill="url(#paint7_linear)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M247.899 39.686C247.692 39.3273 247.234 39.2045 246.875 39.4116L175.336 80.7226C174.977 80.9297 174.854 81.3884 175.061 81.7471C175.269 82.1059 175.727 82.2287 176.086 82.0216L247.625 40.7106C247.984 40.5035 248.106 40.0447 247.899 39.686Z" fill="url(#paint8_linear)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M247.899 48.8583C247.692 48.4996 247.233 48.3769 246.875 48.5841L191.245 80.7227C190.886 80.9299 190.764 81.3886 190.971 81.7473C191.178 82.1059 191.637 82.2287 191.995 82.0215L247.625 49.8829C247.984 49.6757 248.106 49.217 247.899 48.8583Z" fill="url(#paint9_linear)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M247.899 58.0307C247.692 57.6721 247.233 57.5493 246.875 57.7565L207.119 80.7227C206.76 80.9299 206.638 81.3886 206.845 81.7473C207.052 82.1059 207.511 82.2287 207.869 82.0215L247.625 59.0553C247.984 58.8481 248.106 58.3894 247.899 58.0307Z" fill="url(#paint10_linear)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M222.754 -1.62469C222.547 -1.26591 222.67 -0.807252 223.029 -0.600248L246.875 13.1583C247.234 13.3653 247.692 13.2423 247.9 12.8835C248.107 12.5247 247.983 12.0661 247.625 11.8591L223.778 -1.8995C223.42 -2.10651 222.961 -1.98347 222.754 -1.62469ZM190.971 -1.62475C190.764 -1.26599 190.887 -0.807319 191.245 -0.600282L246.875 31.5031C247.234 31.7101 247.692 31.5871 247.899 31.2283C248.107 30.8696 247.984 30.4109 247.625 30.2039L191.995 -1.89947C191.636 -2.1065 191.178 -1.98351 190.971 -1.62475ZM206.88 -1.62485C206.673 -1.26613 206.796 -0.80744 207.155 -0.600344L246.875 22.3306C247.234 22.5377 247.692 22.4148 247.899 22.0561C248.107 21.6973 247.984 21.2386 247.625 21.0315L207.904 -1.89941C207.546 -2.1065 207.087 -1.98358 206.88 -1.62485Z" fill="#F04E54"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M247.899 67.2027C247.692 66.8442 247.233 66.7216 246.874 66.929L223.028 80.7229C222.669 80.9303 222.547 81.3891 222.754 81.7476C222.962 82.1062 223.421 82.2287 223.779 82.0213L247.625 68.2275C247.984 68.0201 248.106 67.5613 247.899 67.2027Z" fill="url(#paint11_linear)"/>
</g>
<defs>
<linearGradient id="paint0_linear" x1="144.179" y1="40.0474" x2="0.54483" y2="40.0474" gradientUnits="userSpaceOnUse">
<stop stop-color="#F04E54" stop-opacity="0"/>
<stop offset="0.601279" stop-color="#F04E54"/>
</linearGradient>
<linearGradient id="paint1_linear" x1="152.129" y1="37.7521" x2="16.4447" y2="37.7521" gradientUnits="userSpaceOnUse">
<stop stop-color="#F04E54" stop-opacity="0"/>
<stop offset="0.597199" stop-color="#F04E54"/>
</linearGradient>
<linearGradient id="paint2_linear" x1="160.078" y1="35.4568" x2="32.3459" y2="35.4568" gradientUnits="userSpaceOnUse">
<stop stop-color="#F04E54" stop-opacity="0"/>
<stop offset="0.592611" stop-color="#F04E54"/>
</linearGradient>
<linearGradient id="paint3_linear" x1="168.028" y1="33.1615" x2="48.2463" y2="33.1615" gradientUnits="userSpaceOnUse">
<stop stop-color="#F04E54" stop-opacity="0"/>
<stop offset="0.587415" stop-color="#F04E54"/>
</linearGradient>
<linearGradient id="paint4_linear" x1="175.978" y1="30.8662" x2="64.1465" y2="30.8662" gradientUnits="userSpaceOnUse">
<stop stop-color="#F04E54" stop-opacity="0"/>
<stop offset="0.581479" stop-color="#F04E54"/>
</linearGradient>
<linearGradient id="paint5_linear" x1="188.884" y1="30.8916" x2="85.004" y2="30.8916" gradientUnits="userSpaceOnUse">
<stop stop-color="#F04E54" stop-opacity="0"/>
<stop offset="0.574635" stop-color="#F04E54"/>
</linearGradient>
<linearGradient id="paint6_linear" x1="195.59" y1="81.6273" x2="195.59" y2="39.7836" gradientUnits="userSpaceOnUse">
<stop offset="0.1119" stop-color="#CF4A4F"/>
<stop offset="0.6877" stop-color="#F04E54"/>
</linearGradient>
<linearGradient id="paint7_linear" x1="179.69" y1="81.6268" x2="179.69" y2="39.7838" gradientUnits="userSpaceOnUse">
<stop offset="0.1119" stop-color="#CF4A4F"/>
<stop offset="0.6877" stop-color="#F04E54"/>
</linearGradient>
<linearGradient id="paint8_linear" x1="211.492" y1="81.6267" x2="211.492" y2="39.7836" gradientUnits="userSpaceOnUse">
<stop offset="0.1119" stop-color="#CF4A4F"/>
<stop offset="0.6877" stop-color="#F04E54"/>
</linearGradient>
<linearGradient id="paint9_linear" x1="219.441" y1="81.6273" x2="219.441" y2="48.9628" gradientUnits="userSpaceOnUse">
<stop offset="0.1119" stop-color="#CF4A4F"/>
<stop offset="0.6877" stop-color="#F04E54"/>
</linearGradient>
<linearGradient id="paint10_linear" x1="227.389" y1="81.6274" x2="227.389" y2="58.1437" gradientUnits="userSpaceOnUse">
<stop offset="0.1119" stop-color="#CF4A4F"/>
<stop offset="0.6877" stop-color="#F04E54"/>
</linearGradient>
<linearGradient id="paint11_linear" x1="235.337" y1="81.6273" x2="235.337" y2="67.3245" gradientUnits="userSpaceOnUse">
<stop offset="0.1119" stop-color="#CF4A4F"/>
<stop offset="0.6877" stop-color="#F04E54"/>
</linearGradient>
</defs>
</svg>
<svg width="1" height="1" xmlns="http://www.w3.org/2000/svg"></svg>

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 68 B

@@ -284,7 +284,7 @@ module('Acceptance | authentication', function (hooks) {
await click(SIGNOUT_BTN);
assert.dom(MODAL_CLOSE_SESSIONS).isVisible();
assert.dom(MODAL_CLOSE_SESSIONS).includesText('Sign out of Boundary?');
assert.dom(MODAL_CLOSE_SESSIONS).includesText('Sign out of Threshold?');
await click(MODAL_CANCEL_BTN);
@@ -313,7 +313,7 @@ module('Acceptance | authentication', function (hooks) {
await click(SIGNOUT_BTN);
assert.dom(MODAL_CLOSE_SESSIONS).isVisible();
assert.dom(MODAL_CLOSE_SESSIONS).includesText('Sign out of Boundary?');
assert.dom(MODAL_CLOSE_SESSIONS).includesText('Sign out of Threshold?');
await click(MODAL_CONFIRM_BTN);
@@ -343,7 +343,7 @@ module('Acceptance | authentication', function (hooks) {
await click(SIGNOUT_BTN);
assert.dom(MODAL_CLOSE_SESSIONS).isVisible();
assert.dom(MODAL_CLOSE_SESSIONS).includesText('Sign out of Boundary?');
assert.dom(MODAL_CLOSE_SESSIONS).includesText('Sign out of Threshold?');
await triggerEvent(window, 'onAppQuit');
@@ -218,7 +218,7 @@ module('Acceptance | projects | settings | index', function (hooks) {
await click(SIGNOUT_BTN);
assert.dom(MODAL_CLOSE_SESSIONS).isVisible();
assert.dom(MODAL_CLOSE_SESSIONS).includesText('Sign out of Boundary?');
assert.dom(MODAL_CLOSE_SESSIONS).includesText('Sign out of Threshold?');
await click(MODAL_CONFIRM_BTN);
+6 -6
View File
@@ -317,7 +317,7 @@ module('Acceptance | scopes', function (hooks) {
isMac: false,
isLinux: false,
});
this.server.get('https://api.releases.hashicorp.com/*', () => {
this.server.get('https://releases-api.threshold.invalid/*', () => {
return new Response(200, {}, META_DATA_RESPONSE);
});
this.server.get('/scopes', () => {
@@ -344,7 +344,7 @@ module('Acceptance | scopes', function (hooks) {
// no "response_type" field
return new Response(200, {}, { scopes: [] });
});
this.server.get('https://api.releases.hashicorp.com/*', () => {
this.server.get('https://releases-api.threshold.invalid/*', () => {
return new Response(200, {}, META_DATA_RESPONSE);
});
@@ -367,7 +367,7 @@ module('Acceptance | scopes', function (hooks) {
// no "response_type" field
return new Response(200, {}, { scopes: [] });
});
this.server.get('https://api.releases.hashicorp.com/*', () => {
this.server.get('https://releases-api.threshold.invalid/*', () => {
return new Response(200, {}, META_DATA_RESPONSE);
});
@@ -390,7 +390,7 @@ module('Acceptance | scopes', function (hooks) {
// no "response_type" field
return new Response(200, {}, { scopes: [] });
});
this.server.get('https://api.releases.hashicorp.com/*', () => {
this.server.get('https://releases-api.threshold.invalid/*', () => {
return new Response(500);
});
@@ -400,7 +400,7 @@ module('Acceptance | scopes', function (hooks) {
assert.dom('[data-test-unsupported-controller-alert]').exists();
assert
.dom('[data-test-releases-link]')
.hasAttribute('href', 'https://releases.hashicorp.com/boundary-desktop/');
.hasAttribute('href', 'https://releases.threshold.invalid/');
});
test('pagination is not supported - navigate to cluster url page', async function (assert) {
@@ -415,7 +415,7 @@ module('Acceptance | scopes', function (hooks) {
// no "response_type" field
return new Response(200, {}, { scopes: [] });
});
this.server.get('https://api.releases.hashicorp.com/*', () => {
this.server.get('https://releases-api.threshold.invalid/*', () => {
return new Response(200, {}, META_DATA_RESPONSE);
});