Compare commits

..
Author SHA1 Message Date
hashicc cd3fc5cea7 fix: 🐛 apply .sr-only fix to all instances 2025-12-11 10:08:17 -08:00
2336 changed files with 16728 additions and 23526 deletions

No files matched your search

+2 -1
View File
@@ -2,12 +2,13 @@ schema_version = 1
project {
license = "BUSL-1.1"
copyright_year = 2021
copyright_year = 2024
# (OPTIONAL) A list of globs that should not have copyright/license headers.
# Supports doublestar glob patterns for more flexibility in defining which
# files or folders should be ignored
header_ignore = [
".github/**",
".husky/**",
"**/node_modules/**",
"**/dist/**",
-91
View File
@@ -1,91 +0,0 @@
name: ci
on:
push:
branches: [main]
tags-ignore: ["**"]
workflow_dispatch:
schedule:
- cron: "41 5 * * *" # nightly: dependency audit + full test run
# One job on purpose: the shared runner pool is small, so everything runs
# sequentially on a single runner instead of a matrix.
jobs:
check:
runs-on: ubuntu-latest
timeout-minutes: 90
env:
CI: "true"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
- name: install pnpm
run: |
npm install -g pnpm@10.33.3
pnpm --version
- name: install dependencies
# Lifecycle scripts are skipped: the desktop postinstall compiles
# electron-app native modules, which the admin build and ember tests
# do not need.
run: pnpm install --frozen-lockfile --ignore-scripts
- name: install headless chrome
# Debian/Ubuntu chromium from the distro archive (fast, mirrored),
# exposed under the name testem's "Chrome" launcher looks for.
shell: bash
run: |
set -euo pipefail
if ! command -v google-chrome >/dev/null 2>&1; then
SUDO=""; [ "$(id -u)" -ne 0 ] && SUDO="sudo"
export DEBIAN_FRONTEND=noninteractive
$SUDO apt-get update -qq
$SUDO apt-get install -y -qq --no-install-recommends chromium \
|| $SUDO apt-get install -y -qq --no-install-recommends chromium-browser
CHROME_BIN=$(command -v chromium || command -v chromium-browser)
mkdir -p "$HOME/bin"
ln -sf "$CHROME_BIN" "$HOME/bin/google-chrome"
echo "$HOME/bin" >> "$GITHUB_PATH"
fi
PATH="$HOME/bin:$PATH" google-chrome --version
- name: build admin ui
run: pnpm --filter admin build
- name: test addons
run: |
for a in core auth rose; do
echo "::group::addons/$a"
(cd addons/$a && npx ember test --test-port 0)
echo "::endgroup::"
done
echo "::group::addons/api"
(cd addons/api && npx ember exam --test-port 0 --split=4 --parallel=1)
echo "::endgroup::"
- name: test desktop ui
run: cd ui/desktop && npx ember test --test-port 0
- name: test admin ui
# The test build is made once and the partitions then run against the
# static output, one browser at a time. Rebuilding in-process (and four
# concurrent browsers) stalled on the small shared runners.
run: |
cd ui/admin
npx ember build --environment=test --output-path="$RUNNER_TEMP/admin-test-dist"
for p in 1 2 3 4; do
echo "::group::admin partition $p/4"
timeout 25m npx ember exam --test-port 0 --path "$RUNNER_TEMP/admin-test-dist" --split=4 --partition=$p
echo "::endgroup::"
done
- name: dependency audit
# Fails on critical advisories only; remaining high/moderate advisories
# are build/test tooling and are tracked in pnpm-overrides.md.
run: |
pnpm audit --audit-level=critical
(cd ui/desktop/electron-app && pnpm audit --audit-level=critical)
+2
View File
@@ -0,0 +1,2 @@
# Anyone attached to this rule will always been assigned to a pull request
* @hashicorp/boundary-ui
+67
View File
@@ -0,0 +1,67 @@
---
name: Bug report
about: Let us know about a bug!
title: ''
labels: ''
assignees: ''
---
<!-- Please reserve GitHub issues for bug reports and feature requests.
For questions, the best place to get answers is on our [discussion forum](https://discuss.hashicorp.com/c/boundary), as they will get more visibility from experienced users than the issue tracker.
Please note: We take Boundary's security and our users' trust very seriously. If you believe you have found a security issue in Boundary, please responsibly disclose this by contacting us at security@hashicorp.com. Our PGP key is available on [our security page](https://www.hashicorp.com/security/).
Logging is available on Boundary Desktop Client version >= 2.1.0
Logs are found at:
Linux: ~/.config/Boundary/logs/desktop-client.log
MacOS: ~/Library/Logs/Boundary/desktop-client.log
Windows: $env:USERPROFILE\AppData\Roaming\Boundary\logs\desktop-client.log
If requests are taking longer than expected, please change the logging level to DEBUG. This will log the cache daemon request times as well.
-->
## :bug: Bug Report
### **Description**
_A clear and concise description of the bug._
### **Steps to Reproduce**
1. Go to '...'
2. Click on '...'
3. Scroll down to '...'
4. See the error
## **Expected behavior**
_A clear description of what you expected to happen._
## **Actual behavior**
_A clear description of what actually happened._
## **Screenshots (if applicable)**
_Add screenshots or screen recordings to help explain the issue._
## **Environment**
- **OS and Version:** (e.g., Windows 10 (22H2), macOS (14.7.2))
- **Architecture:** (e.g., arm64, x86_64)
- **Browser/Version:** (if applicable)
- **Desktop Client Version:** (if applicable)
- **Controller/worker versions:** (if applicable)
## **Logs & Console Output (if applicable)**
_Paste any relevant error logs or browser console output here._
## **Additional Context**
_Any other details that might be relevant._
+7
View File
@@ -0,0 +1,7 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
contact_links:
- name: Ask a question
url: https://discuss.hashicorp.com/c/boundary
about: For increased visibility, please post questions on the discussion forum.
+23
View File
@@ -0,0 +1,23 @@
---
name: Feature request
about: Suggest something!
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Explain any additional use-cases**
If there are any use-cases that would help us understand the use/need/value please share them as they can help us decide on acceptance and prioritization.
**Additional context**
Add any other context or screenshots about the feature request here.
+6
View File
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
+30
View File
@@ -0,0 +1,30 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
addons:
- changed-files:
- any-glob-to-any-file: "addons/**/*"
api-addon:
- changed-files:
- any-glob-to-any-file: "addons/api/**/*"
auth-addon:
- changed-files:
- any-glob-to-any-file: "addons/auth/**/*"
styles-addon:
- changed-files:
- any-glob-to-any-file: "addons/rose/**/*"
ui:
- changed-files:
- any-glob-to-any-file: "ui/**/*"
admin:
- changed-files:
- any-glob-to-any-file: "ui/admin/**/*"
desktop:
- changed-files:
- any-glob-to-any-file: "ui/desktop/**/*"
+33
View File
@@ -0,0 +1,33 @@
# Description
<!-- Add a brief description of changes here -->
<!-- Uncomment line below to manually add link to JIRA ticket -->
<!-- :tickets: [Jira ticket](https://hashicorp.atlassian.net/browse/JIRA_TICKET_NUMBER) -->
## Screenshots (if appropriate)
## How to Test
<!-- Add steps to test this change. Include any other necessary relevant links -->
## Checklist
<!-- strikethrough the checklist item that is not relevant to your change -->
<!-- If you are merging a long lived branch, major feature, or UI altering changes,
please add the a11y-tests label. Other cases, like a dependency change or
translation update likely does not need an a11y audit -->
- [ ] I have added before and after screenshots for UI changes
- [ ] I have added JSON response output for API changes
- [ ] I have added steps to reproduce and test for bug fixes in the description
- [ ] I have commented on my code, particularly in hard-to-understand areas
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] I have added `a11y-tests` label to run a11y audit tests if needed
## PCI review checklist
<!-- heimdall_github_prtemplate:grc-pci_dss-2024-01-05 -->
- [ ] I have documented a clear reason for, and description of, the change I am making.
- [ ] If applicable, I've documented a plan to revert these changes if they require more than reverting the pull request.
- [ ] If applicable, I've documented the impact of any changes to security controls.
Examples of changes to security controls include using new access control methods, adding or removing logging pipelines, etc.
+94
View File
@@ -0,0 +1,94 @@
#!/usr/bin/env bash
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
set -euo pipefail
# Configure Git
git config --global user.email "hc-github-team-secure-boundary@hashicorp.com"
git config --global user.name "github-team-secure-boundary"
# Fetch branches from ENT
git fetch origin
BRANCH=${1}
echo "BRANCH to merge is $BRANCH"
git checkout "${BRANCH}"
# Checkout OSS repo
git remote add oss-remote https://github.com/hashicorp/boundary-ui.git
git fetch oss-remote
# Merge oss/${BRANCH} into ent/${BRANCH}
git_merge_branch="${2}"
git checkout -b "${git_merge_branch}"
latest_oss_commit="$(git rev-parse --short oss-remote/${BRANCH})"
echo "Trying to merge the latest oss commit - ${latest_oss_commit} from oss/${BRANCH} into ent/${BRANCH}"
if ! errors=$(git merge -m "Merge Boundary UI OSS branch '${BRANCH}' at commit ${latest_oss_commit}" "${latest_oss_commit}"); then
# Here we can try to auto resolve conflicts
# This logic will vary from project to project. The below is just an example.
conflicts=$(git diff --name-only --diff-filter=U)
printf "Found conflicts:\n${conflicts}\n"
# Resolve package.json conflicts by taking oss
if echo "$conflicts" | grep -q package.json; then
echo "Checking out oss package.json..."
git checkout --theirs package.json
git add package.json
fi
# Resolve pnpm-lock.yaml conflicts by re-running pnpm install:
# https://pnpm.io/git#merge-conflicts
if echo "$conflicts" | grep -q pnpm-lock.yaml; then
echo "Re-running pnpm install to fix conflicts by regenerating pnpm-lock.yaml..."
pnpm install
git add pnpm-lock.yaml
fi
# If we can commit all the changes without conflict, we have resolved everything automatically
if ! git commit --no-edit; then
echo "Auto Merge failed, creating a draft PR"
git merge --abort
git clean -xfd
git fetch oss-remote
git checkout "${OSS_BRANCH}"
git checkout -b "${OSS_LOCAL_BRANCH}"
git push -f --set-upstream origin "${OSS_LOCAL_BRANCH}"
gh pr create \
--draft \
--fill-first \
--label "oss-merge" \
-B "${BASE_BRANCH}" \
-H "${OSS_LOCAL_BRANCH}" \
-a "${ACTOR}" \
-t "[${BASE_BRANCH/oss\/release\//}] OSS to ENT merge of (${SHA::7})" \
-b "${BASE_BRANCH/oss\//} upstream merge of (${SHA::7})
Merge failed, Please fix the conflicts using github UI or using the following commands:
\`\`\`bash
git checkout ${BASE_BRANCH}
git pull
git checkout ${OSS_LOCAL_BRANCH}
git merge ${BASE_BRANCH}
# fix conflicts and commit
git push origin ${OSS_LOCAL_BRANCH}
\`\`\`"
exit 0
fi
fi
# Check that there are actually changes to merge by comparing the
# merge branch to the current checked out branch
if (git diff ${BRANCH} --exit-code > /dev/null); then
echo "there are no changes to merge"
exit 0
fi
git push origin "${git_merge_branch}"
gh pr create \
--fill-first \
--label "oss-merge" \
-B "${BASE_BRANCH}" \
-H "${MERGE_BRANCH}" \
-a ${ACTOR} \
-t "[${BASE_BRANCH/oss\/release\//}] OSS to ENT merge of (${SHA::7})" \
-b "${BASE_BRANCH/oss\//} upstream merge of (${SHA::7})"
gh pr merge --auto --merge
# This PR will be need to be approved manually
+56
View File
@@ -0,0 +1,56 @@
name: A11y Tests
on:
pull_request:
types: [labeled, opened, synchronize, reopened]
workflow_dispatch:
jobs:
a11y-test:
name: Run A11y Tests
if: contains(github.event.pull_request.labels.*.name, 'a11y-tests')
runs-on: ${{ fromJSON(vars.RUNNER) }}
timeout-minutes: 40
steps:
- uses: browser-actions/setup-chrome@b94431e051d1c52dcbe9a7092a4f10f827795416 # v2.1.0
with:
install-dependencies: true
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
with:
run_install: false
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 20
cache: 'pnpm'
cache-dependency-path: '**/pnpm-lock.yaml'
- run: pnpm install
- name: Run a11y tests
env:
# this will generate the test reports but causes tests to pass even when there a11y failures
ENABLE_A11Y_MIDDLEWARE_REPORTER: true
run: pnpm test-a11y
- name: Consolidate ember a11y reports
run: |
mkdir ember-a11y-reports
jq -s 'map(.[])' ./ui/admin/ember-a11y-report/*.json > ember-a11y-reports/admin.json
jq -s 'map(.[])' ./ui/desktop/ember-a11y-report/*.json > ember-a11y-reports/desktop.json
- name: Output ember a11y test report summary (admin)
run: 'cat ember-a11y-reports/admin.json | jq "map({moduleName,testName,routes,urls,violations: .violations | map({id, nodes: .nodes | map({failureSummary, targets: .[].[]?.relatedNodes?.[]?.target? })}) })"'
- name: Output ember a11y test report summary (desktop)
run: 'cat ember-a11y-reports/desktop.json | jq "map({moduleName,testName,routes,urls,violations: .violations | map({id, nodes: .nodes | map({failureSummary, targets: .[].[]?.relatedNodes?.[]?.target? })}) })"'
- name: Upload ember a11y reports
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: ember-a11y-reports
path: ./ember-a11y-reports
- name: Report a11y test results status
if: always()
# fail CI when the combined array length of admin and desktop a11y reports is not 0
run: |
EMBER_A11Y_FAILURE_COUNT=$(jq -s 'map(.[]) | length' ember-a11y-reports/admin.json ember-a11y-reports/desktop.json)
echo "$EMBER_A11Y_FAILURE_COUNT ember-a11y test failures"
if [ "$EMBER_A11Y_FAILURE_COUNT" != '0' ]; then
exit 1
fi
+94
View File
@@ -0,0 +1,94 @@
name: Build Admin UI
on:
push:
branches:
- main
- "release/**"
workflow_dispatch:
jobs:
dependencies:
name: Install dependencies
runs-on: ${{ fromJSON(vars.RUNNER) }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
with:
run_install: false
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 20
cache: 'pnpm'
cache-dependency-path: '**/pnpm-lock.yaml'
- run: pnpm install --frozen-lockfile
build-admin-ui-oss:
name: Build Admin UI OSS
needs: [dependencies]
runs-on: ${{ fromJSON(vars.RUNNER) }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
with:
run_install: false
- name: Build
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 20
cache: 'pnpm'
cache-dependency-path: '**/pnpm-lock.yaml'
- run: pnpm install --offline
- run: pnpm run build:ui:admin:oss
- name: Upload artifact admin-ui
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: admin-ui
path: ./ui/admin/dist/
- name: Upload artifact OSS admin UI
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: admin-ui-oss
path: ./ui/admin/dist/
build-admin-ui-enterprise:
name: Build Admin UI Enterprise
needs: [dependencies]
runs-on: ${{ fromJSON(vars.RUNNER) }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
with:
run_install: false
- name: Build
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 20
cache: 'pnpm'
cache-dependency-path: '**/pnpm-lock.yaml'
- run: pnpm install --offline
- run: pnpm run build:ui:admin:enterprise
- name: Upload artifact enterprise admin UI
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: admin-ui-ent
path: ./ui/admin/dist/
build-admin-ui-hcp:
name: Build Admin UI HCP
needs: [dependencies]
runs-on: ${{ fromJSON(vars.RUNNER) }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
with:
run_install: false
- name: Build
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 20
cache: 'pnpm'
cache-dependency-path: '**/pnpm-lock.yaml'
- run: pnpm install --offline
- run: pnpm run build:ui:admin:hcp
- name: Upload artifact HCP admin UI
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: admin-ui-hcp
path: ./ui/admin/dist/
+57
View File
@@ -0,0 +1,57 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
name: "CodeQL"
on:
push:
branches: [main]
pull_request:
# The branches below must be a subset of the branches above
branches: [main]
schedule:
- cron: '0 19 * * 4'
jobs:
analyze:
name: Analyze
runs-on: ${{ fromJSON(vars.RUNNER) }}
strategy:
fail-fast: false
matrix:
# Override automatic language detection by changing the below list
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
language: ['javascript']
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@70df9def86d22bf0ea4e7f8b956e7b92e7c1ea22 # codeql-bundle-v2.20.7
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@70df9def86d22bf0ea4e7f8b956e7b92e7c1ea22 # codeql-bundle-v2.20.7
+19
View File
@@ -0,0 +1,19 @@
name: Add Copyright Headers
on: pull_request
jobs:
copywrite:
runs-on: ${{ fromJSON(vars.RUNNER) }}
permissions:
contents: write
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
# Ref and repository aren't normally needed, this is a workaround for a bug in auto commit
with:
ref: ${{ github.event.pull_request.head.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
- uses: hashicorp/setup-copywrite@32638da2d4e81d56a0764aa1547882fc4d209636 # v1.1.3
- name: Add missing Copyright Headers
run: copywrite headers
- uses: stefanzweifel/git-auto-commit-action@28e16e81777b558cc906c8750092100bbb34c5e3 # v7.0.0
with:
commit_message: Add missing copyright headers
+107
View File
@@ -0,0 +1,107 @@
on:
issues:
types: [opened, closed, deleted, reopened]
pull_request_target:
types: [opened, closed, reopened]
issue_comment: # Also triggers when commenting on a PR from the conversation view
types: [created]
workflow_dispatch:
name: Jira Sync
jobs:
sync:
runs-on: ${{ fromJSON(vars.RUNNER) }}
name: Jira sync
steps:
- name: Check if community user
if: github.event.action == 'opened'
id: boundary-team-role
run: |
TEAM=boundary
ROLE="$(gh api orgs/hashicorp/teams/${TEAM}/memberships/${{ github.actor }} | jq -r '.role | select(.!=null)')"
if [[ -n ${ROLE} ]]; then
echo "Actor ${{ github.actor }} is a ${TEAM} team member, skipping ticket creation"
else
echo "Actor ${{ github.actor }} is not a ${TEAM} team member"
fi
echo "role=${ROLE}" >> $GITHUB_OUTPUT
env:
GITHUB_TOKEN: ${{ secrets.JIRA_SYNC_GITHUB_TOKEN }}
- name: Set ticket type
if: github.event.action == 'opened' && !steps.boundary-team-role.outputs.role
id: set-ticket-type
run: |
if [[ "${{ github.event_name }}" == "pull_request_target" ]]; then
echo "type=PR" >> $GITHUB_OUTPUT
else
echo "type=ISS" >> $GITHUB_OUTPUT
fi
- name: Create ticket
if: github.event.action == 'opened' && !steps.boundary-team-role.outputs.role
uses: tomhjp/gh-action-jira-create@3ed1789cad3521292e591a7cfa703215ec1348bf # v0.2.1
env:
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
with:
project: ICU
issuetype: "GH Issue"
summary: "${{ github.event.repository.name }} [${{ steps.set-ticket-type.outputs.type }} #${{ github.event.issue.number || github.event.pull_request.number }}]: ${{ github.event.issue.title || github.event.pull_request.title }}"
description: "${{ github.event.issue.body || github.event.pull_request.body }}\n\n_Created from GitHub Action for ${{ github.event.issue.html_url || github.event.pull_request.html_url }}, from ${{ github.actor }}_"
# customfield_10089 is Issue Link custom field
# customfield_10091 is team custom field
extraFields: '{"customfield_10089": "${{ github.event.issue.html_url || github.event.pull_request.html_url }}"}'
- name: Search
if: github.event.action != 'opened'
id: search
uses: tomhjp/gh-action-jira-search@04700b457f317c3e341ce90da5a3ff4ce058f2fa # v0.2.2
env:
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
with:
# cf[10089] is Issue Link custom field
jql: 'issuetype = "GH Issue" and cf[10089]="${{ github.event.issue.html_url || github.event.pull_request.html_url }}"'
- name: Sync comment
if: github.event.action == 'created' && steps.search.outputs.issue
uses: tomhjp/gh-action-jira-comment@6eb6b9ead70221916b6badd118c24535ed220bd9 # v0.2.0
env:
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
with:
issue: ${{ steps.search.outputs.issue }}
comment: "${{ github.actor }} ${{ github.event.review.state || 'commented' }}:\n\n${{ github.event.comment.body || github.event.review.body }}\n\n${{ github.event.comment.html_url || github.event.review.html_url }}"
- name: Transitions
id: transitions
if: steps.search.outputs.issue
run: |
if [[ "${{ github.event.action }}" == "closed" || "${{ github.event.action }}" == "deleted" ]]; then
echo "Closing ticket"
echo "name=Done" >> "$GITHUB_OUTPUT"
elif [[ "${{ github.event.action }}" == "reopened" ]]; then
echo "Reopening ticket"
echo "name=Reopen" >> "$GITHUB_OUTPUT"
fi
# Transition issue API reference: https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-issueidorkey-transitions-post
- name: Transition ticket
if: steps.transitions.outputs.name
run: |
transitions="$(curl --silent \
--url "${{ secrets.JIRA_BASE_URL }}rest/api/3/issue/${{ steps.search.outputs.issue }}/transitions" \
--user "${{ secrets.JIRA_USER_EMAIL }}:${{ secrets.JIRA_API_TOKEN }}" \
--header "Accept: application/json")"
id="$(echo "${transitions}" | jq -r '.transitions[] | select(.name == "${{ steps.transitions.outputs.name }}") | .id')"
curl --silent \
--url "${{ secrets.JIRA_BASE_URL }}rest/api/3/issue/${{ steps.search.outputs.issue }}/transitions" \
--user "${{ secrets.JIRA_USER_EMAIL }}:${{ secrets.JIRA_API_TOKEN }}" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--data "$(printf '{"transition": {"id": "%s"}}' "${id}")"
+11
View File
@@ -0,0 +1,11 @@
name: "Pull Request Labeler"
on:
- pull_request_target
jobs:
triage:
runs-on: ${{ fromJSON(vars.RUNNER) }}
steps:
- uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
+74
View File
@@ -0,0 +1,74 @@
name: Validate Monorepo
on: pull_request
jobs:
dependencies:
name: Install dependencies
runs-on: ${{ fromJSON(vars.RUNNER) }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
with:
run_install: false
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 20
cache: 'pnpm'
cache-dependency-path: '**/pnpm-lock.yaml'
- run: pnpm install --frozen-lockfile
compliance:
name: License Compliance
needs: [dependencies]
runs-on: ${{ fromJSON(vars.RUNNER) }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
with:
run_install: false
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 20
cache: 'pnpm'
cache-dependency-path: '**/pnpm-lock.yaml'
- run: pnpm install --offline
- run: pnpm run compliance:licenses
lint:
name: Lint
needs: [dependencies, compliance]
runs-on: ${{ fromJSON(vars.RUNNER) }}
timeout-minutes: 5
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
with:
run_install: false
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 20
cache: 'pnpm'
cache-dependency-path: '**/pnpm-lock.yaml'
- run: pnpm install --offline
- run: pnpm lint
test:
name: Test
needs: [lint]
runs-on: ${{ fromJSON(vars.RUNNER) }}
timeout-minutes: 15
steps:
- uses: browser-actions/setup-chrome@b94431e051d1c52dcbe9a7092a4f10f827795416 # v2.1.0
with:
install-dependencies: true
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
with:
run_install: false
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 20
cache: 'pnpm'
cache-dependency-path: '**/pnpm-lock.yaml'
- run: pnpm install --offline
- run: pnpm test
@@ -0,0 +1,25 @@
name: Trigger OSS to Enterprise Merge
on:
pull_request_target:
types:
- closed
branches:
- main
jobs:
trigger-oss-merge:
# Run this only on merge events in OSS repo
if: ${{ github.event.pull_request.merged && github.repository == 'hashicorp/boundary-ui' }}
runs-on: ${{ fromJSON(vars.RUNNER) }}
steps:
- name: Trigger Merge
env:
GIT_REF: ${{ github.ref_name }}
GIT_SHA: ${{ github.sha }}
GH_PAT: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
GIT_ACTOR: ${{ github.actor }}
run: |
curl -H "Authorization: token $GH_PAT" \
-H 'Accept: application/json' \
-d "{\"event_type\": \"oss-merge\", \"client_payload\": {\"git-ref\": \"${GIT_REF}\", \"git-sha\": \"${GIT_SHA}\", \"git-actor\": \"${GIT_ACTOR}\" }}" \
"https://api.github.com/repos/hashicorp/boundary-ui-enterprise/dispatches"
+24
View File
@@ -0,0 +1,24 @@
name: OSS → ENT Merge
on:
repository_dispatch:
types: [ oss-merge ]
jobs:
oss-merge:
runs-on: ${{ fromJSON(vars.RUNNER) }}
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
token: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
- run: |
git fetch --prune --unshallow
./.github/scripts/merge.sh "${BASE_BRANCH}" "${MERGE_BRANCH}"
env:
BASE_BRANCH: ${{ github.event.client_payload.git-ref }}
OSS_BRANCH: oss-remote/${{ github.event.client_payload.git-ref }}
OSS_LOCAL_BRANCH: oss/${{ github.event.client_payload.git-ref }}-${{ github.event.client_payload.git-sha }}
MERGE_BRANCH: oss/merge-${{ github.event.client_payload.git-ref }}-${{github.event.client_payload.git-sha}}
GITHUB_TOKEN: ${{secrets.ELEVATED_GITHUB_TOKEN }}
MERGE_APPROVE_TOKEN: ${{secrets.ELEVATED_GITHUB_TOKEN }}
ACTOR: ${{ github.event.client_payload.git-actor }}
SHA: ${{github.event.client_payload.git-sha}}
+207
View File
@@ -0,0 +1,207 @@
name: Test E2E Admin UI
on:
pull_request:
types: [labeled, opened, synchronize, reopened]
paths:
- 'ui/admin/**'
- 'e2e-tests/*'
- 'e2e-tests/api-client/**'
- 'e2e-tests/helpers/**'
- 'e2e-tests/admin/**'
- '.github/workflows/test-e2e-admin-ui.yaml'
workflow_dispatch:
inputs:
boundary-enterprise-branch:
description: 'Branch of boundary-enterprise to test against (default to main)'
required: true
default: 'main'
type: string
boundary-branch:
description: 'Branch of boundary to test against (default to main)'
required: true
default: 'main'
type: string
jobs:
test:
name: test
runs-on: ${{ fromJSON(vars.RUNNER_UBUNTU_22) }}
strategy:
matrix:
include:
- boundary_edition: community
github_repo: hashicorp/boundary
folder_name: boundary
boundary_edition_short: oss
enos_scenario: e2e_ui_docker
test_command: admin:ce:docker
boundary_branch: ${{ github.event.inputs.boundary-branch || 'main' }}
- boundary_edition: enterprise
github_repo: hashicorp/boundary-enterprise
folder_name: boundary-enterprise
boundary_edition_short: ent
enos_scenario: e2e_ui_docker_ent
test_command: admin:ent:docker
boundary_branch: ${{ github.event.inputs.boundary-enterprise-branch || 'main' }}
fail-fast: false
env:
ENOS_VAR_e2e_debug_no_run: true
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 0
- name: Set up pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
with:
run_install: false
- name: Set up Node
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 20
cache: "pnpm"
cache-dependency-path: |
pnpm-lock.yaml
ui/desktop/electron-app/pnpm-lock.yaml
- name: Set up Terraform
uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd
- name: Set up Enos
uses: hashicorp/action-setup-enos@39a8f388434bea5eeba6649b99aa9949a55a1150
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Vault CLI
run: |
wget https://releases.hashicorp.com/vault/1.12.2/vault_1.12.2_linux_amd64.zip -O /tmp/vault.zip
unzip /tmp/vault.zip -d /usr/local/bin
- name: GPG setup
run: |
# Create a GPG key
export KEY_PW=boundary
gpg --generate-key --batch <<eoGpgConf
%echo Started!
Key-Type: RSA
Key-Length: default
Subkey-Type: RSA
Name-Real: boundary
Name-Comment: default
Name-Email: default
Expire-Date: 0
Passphrase: $KEY_PW
%commit
%echo Done.
eoGpgConf
# Enable gpg-preset-passphrase so that key passwords can be saved
echo "allow-preset-passphrase" >> ~/.gnupg/gpg-agent.conf
gpg-connect-agent reloadagent /bye &>/dev/null
# Get information about the created keys
export lines=$(gpg --list-secret-keys --with-colons --with-keygrip)
export KEY_ID=""
while read -r line
do
# Save the first key id to be used later
if [[ $line =~ "fpr"* ]]; then
if [[ $KEY_ID == "" ]]; then
KEY_ID="$(echo "$line" | sed -r 's/fpr|://g')"
fi
fi
# Cache the passphrases for the keys so passwords do not need to be entered
if [[ $line =~ "grp"* ]]; then
export KEYGRIP_ID="$(echo "$line" | sed -r 's/grp|://g')"
/usr/lib/gnupg/gpg-preset-passphrase --preset -P $KEY_PW $KEYGRIP_ID
fi
done <<< $lines
# Trust the key
touch /tmp/test.txt
gpg -a --encrypt -r $KEY_ID --trust-model always --batch --yes /tmp/test.txt
echo "trusted-key $KEY_ID" >> ~/.gnupg/gpg.conf
# Initialize the password store
pass init $KEY_ID &>/dev/null
- name: Checkout ${{ matrix.folder_name }} repo
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
repository: ${{ matrix.github_repo }}
path: support/src/${{ matrix.folder_name }}
token: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
ref: ${{ matrix.boundary_branch }}
- name: GH fix for localhost resolution
run: |
cat /etc/hosts && echo "-----------"
sudo sed -i 's/::1 *localhost ip6-localhost ip6-loopback/::1 ip6 -localhost ip6-loopback/g' /etc/hosts
cat /etc/hosts
ssh -V
echo "127.0.0.1 localhost boundary" | sudo tee -a /etc/hosts
echo "127.0.0.1 localhost worker" | sudo tee -a /etc/hosts
echo "127.0.0.1 localhost vault" | sudo tee -a /etc/hosts
- name: Set git config
run: |
git config --global url."https://oauth2:${{ secrets.ELEVATED_GITHUB_TOKEN }}@github.com".insteadOf "https://github.com"
- name: Install node dependencies
run: |
pnpm install --frozen-lockfile
cd e2e-tests
pnpm playwright install --with-deps
- name: Set up test infra
id: infra
run: |
ssh-keygen -N '' -t ed25519 -f ~/.ssh/github_enos
mkdir -p ./enos/terraform-plugin-cache
echo ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} > ./support/src/${{matrix.folder_name}}/internal/ui/VERSION
export ENOS_VAR_ui_build_override="oss" && \
export ENOS_VAR_boundary_edition=${{ matrix.boundary_edition_short }} && \
export ENOS_VAR_enos_user=$GITHUB_ACTOR && \
export ENOS_VAR_aws_ssh_private_key_path=~/.ssh/github_enos && \
export ENOS_VAR_boundary_license="${{ secrets.BOUNDARY_ENT_LICENSE }}" && \
enos scenario launch --timeout 60m0s --chdir ./support/src/${{matrix.folder_name}}/enos ${{matrix.enos_scenario}} builder:local
- name: Move boundary binary
run: |
mv ./support/src/${{matrix.folder_name}}/bin/boundary /usr/local/bin/
boundary version
- name: Run Tests
run: |
source <(bash ./support/src/${{matrix.folder_name}}/enos/scripts/test_e2e_env.sh)
cd e2e-tests
pnpm run ${{ matrix.test_command }} --reporter=html
- name: Upload Playwright report
if: ${{ failure() }}
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: playwright-report-${{ matrix.boundary_edition }}
path: e2e-tests/playwright-report
- name: Clean up test infra
if: ${{ always() }}
run: |
export ENOS_VAR_boundary_edition=${{ matrix.boundary_edition_short }} && \
export ENOS_VAR_enos_user=$GITHUB_ACTOR && \
export ENOS_VAR_aws_ssh_private_key_path=~/.ssh/github_enos && \
enos scenario destroy --timeout 60m0s --chdir ./support/src/${{matrix.folder_name}}/enos ${{matrix.enos_scenario}} builder:local
- name: Send Slack message on failure
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
if: ${{ failure() && github.repository == 'hashicorp/boundary-ui' }}
with:
method: chat.postMessage
token: ${{ secrets.SLACK_BOT_TOKEN }}
payload: |
channel: ${{ secrets.SLACK_CHANNEL_ID }}
text: ":x: admin ui e2e tests failed: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Branch:* ${{ github.repository }}:${{ github.head_ref }}"
+128
View File
@@ -0,0 +1,128 @@
name: Test E2E Desktop Client
on:
pull_request:
types: [labeled, opened, synchronize, reopened]
paths:
- 'ui/desktop/**'
- 'e2e-tests/*'
- 'e2e-tests/api-client/**'
- 'e2e-tests/helpers/**'
- 'e2e-tests/desktop/**'
- '.github/workflows/test-e2e-desktop.yaml'
workflow_dispatch:
jobs:
test:
name: test
runs-on: ${{ fromJSON(vars.RUNNER_UBUNTU_22) }}
env:
ENOS_VAR_boundary_edition: "ent"
ENOS_VAR_e2e_debug_no_run: true
SETUP_CLI: true
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 0
- name: Set up pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
with:
run_install: false
- name: Set up Node
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 20
cache: "pnpm"
cache-dependency-path: |
pnpm-lock.yaml
ui/desktop/electron-app/pnpm-lock.yaml
- name: Set up Terraform
uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd
- name: Set up Enos
uses: hashicorp/action-setup-enos@39a8f388434bea5eeba6649b99aa9949a55a1150
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Vault CLI
run: |
wget https://releases.hashicorp.com/vault/1.12.2/vault_1.12.2_linux_amd64.zip -O /tmp/vault.zip
unzip /tmp/vault.zip -d /usr/local/bin
- name: Checkout boundary-enterprise
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
repository: hashicorp/boundary-enterprise
# ref: ${{ github.event.inputs.boundary-enterprise-branch }}
path: support/src/boundary-enterprise
token: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
- name: GH fix for localhost resolution
run: |
cat /etc/hosts && echo "-----------"
sudo sed -i 's/::1 *localhost ip6-localhost ip6-loopback/::1 ip6 -localhost ip6-loopback/g' /etc/hosts
cat /etc/hosts
ssh -V
echo "127.0.0.1 localhost boundary" | sudo tee -a /etc/hosts
echo "127.0.0.1 localhost worker" | sudo tee -a /etc/hosts
echo "127.0.0.1 localhost vault" | sudo tee -a /etc/hosts
# TODO: Build image ourselves in case we don't want to use latest?
- name: Get Boundary docker image
run: |
docker pull hashicorp/boundary-enterprise:latest
docker save hashicorp/boundary-enterprise:latest | gzip > /tmp/boundary-enterprise.zip
- name: Set up test infra
id: infra
run: |
ssh-keygen -N '' -t ed25519 -f ~/.ssh/github_enos
mkdir -p ./enos/terraform-plugin-cache
export ENOS_VAR_enos_user=$GITHUB_ACTOR && \
export ENOS_VAR_aws_ssh_private_key_path=~/.ssh/github_enos && \
export ENOS_VAR_boundary_license="${{ secrets.BOUNDARY_ENT_LICENSE }}" && \
export ENOS_VAR_boundary_docker_image_file=/tmp/boundary-enterprise.zip && \
enos scenario launch --timeout 60m0s --chdir ./support/src/boundary-enterprise/enos e2e_ui_docker_ent builder:crt
- name: Install dependencies
run: |
pnpm install --frozen-lockfile
cd e2e-tests
pnpm playwright install --with-deps
# Runner is headless so we need to enable a display to run the client
- name: Run Tests
run: |
source <(bash ./support/src/boundary-enterprise/enos/scripts/test_e2e_env.sh)
cd e2e-tests
export DISPLAY=:99
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
pnpm run desktop
- name: Upload Playwright report
if: ${{ failure() }}
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: playwright-report
path: e2e-tests/playwright-report
- name: Clean up test infra
if: ${{ always() }}
run: |
export ENOS_VAR_enos_user=$GITHUB_ACTOR && \
export ENOS_VAR_aws_ssh_private_key_path=~/.ssh/github_enos && \
enos scenario destroy --timeout 60m0s --chdir ./support/src/boundary-enterprise/enos e2e_ui_docker_ent builder:crt
- name: Send Slack message on failure
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
if: ${{ failure() && github.repository == 'hashicorp/boundary-ui' }}
with:
method: chat.postMessage
token: ${{ secrets.SLACK_BOT_TOKEN }}
payload: |
channel: ${{ secrets.SLACK_CHANNEL_ID }}
text: ":x: desktop client e2e tests failed: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Branch:* ${{ github.repository }}:${{ github.head_ref }}"
+22
View File
@@ -0,0 +1,22 @@
name: "Trigger Boundary Desktop release"
on:
push:
tags:
- '*'
jobs:
trigger-gha-release:
runs-on: ${{ fromJSON(vars.RUNNER) }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Release description
run: |
echo "Triggering release with a TAG ${GITHUB_REF#refs/tags/}"
- name: Trigger Release workflow in boundary-desktop-releases
run: |
export GITHUB_TOKEN="${{ secrets.ELEVATED_GITHUB_TOKEN }}"
gh workflow run release.yml \
--repo hashicorp/boundary-desktop-releases \
--ref main \
-f TAG="${GITHUB_REF#refs/tags/}"
+6
View File
@@ -0,0 +1,6 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
url_license = "https://github.com/hashicorp/boundary-ui/blob/main/LICENSE"
url_project_website = "https://learn.hashicorp.com/tutorials/boundary/getting-started-desktop-app"
url_source_repository = "https://github.com/hashicorp/boundary-ui"
+7 -7
View File
@@ -3,21 +3,21 @@ License text copyright (c) 2020 MariaDB Corporation Ab, All Rights Reserved.
Parameters
Licensor: International Business Machines Corporation (IBM)
Licensed Work: The Licensed Work is (c) 2024 IBM Corp.
Licensor: HashiCorp, Inc.
Licensed Work: The Licensed Work is (c) 2024 HashiCorp, Inc.
Additional Use Grant: You may make production use of the Licensed Work, provided
Your use does not include offering the Licensed Work to third
parties on a hosted or embedded basis in order to compete with
IBM Corp's paid version(s) of the Licensed Work. For purposes
HashiCorp's paid version(s) of the Licensed Work. For purposes
of this license:
A "competitive offering" is a Product that is offered to third
parties on a paid basis, including through paid support
arrangements, that significantly overlaps with the capabilities
of IBM Corp's paid version(s) of the Licensed Work. If Your
of HashiCorp's paid version(s) of the Licensed Work. If Your
Product is not a competitive offering when You first make it
generally available, it will not become a competitive offering
later due to IBM Corp releasing a new version of the Licensed
later due to HashiCorp releasing a new version of the Licensed
Work with additional capabilities. In addition, Products that
are not provided on a paid basis are not competitive.
@@ -33,10 +33,10 @@ Additional Use Grant: You may make production use of the Licensed Work, provided
Hosting or using the Licensed Work(s) for internal purposes
within an organization is not considered a competitive
offering. IBM Corp considers your organization to include all
offering. HashiCorp considers your organization to include all
of your affiliates under common control.
For binding interpretive guidance on using IBM Corp products
For binding interpretive guidance on using HashiCorp products
under the Business Source License, please visit our FAQ.
(https://www.hashicorp.com/license-faq)
Change Date: Four years from the date the Licensed Work is published.
-28
View File
@@ -1,28 +0,0 @@
Threshold UI
Copyright (c) 2026 CyberCove LLC
This repository is a community fork of "Boundary UI"
(https://github.com/hashicorp/boundary-ui), the admin web UI and desktop
client for HashiCorp Boundary.
Upstream work: Copyright (c) HashiCorp, Inc. 2020-2023;
Copyright (c) IBM Corp. 2024-2026
Upstream license: Business Source License 1.1 (see LICENSE)
The upstream LICENSE and per-file copyright / SPDX headers are retained
unchanged. Modifications made in this fork are provided under the same
license terms (BUSL-1.1), including its Additional Use Grant and Change
Date as stated in LICENSE.
This project is an independent community effort. It is NOT affiliated with,
endorsed by, or sponsored by HashiCorp, Inc. or IBM Corp. "HashiCorp",
"Boundary", and related marks and logos are trademarks of their respective
owners; they are used here only to describe the upstream origin of this work
and to name the upstream CLI/API this software interoperates with. The
upstream logos and brand art have been removed and replaced with plain
placeholder marks.
Third-party components keep their own licenses (see pnpm-lock.yaml and the
`pnpm compliance:licenses` script). The HashiCorp Design System packages
(@hashicorp/design-system-components, -tokens, @hashicorp/flight-icons) are
consumed unmodified from the public npm registry under their own licenses.
+5 -36
View File
@@ -1,41 +1,10 @@
# Threshold UI Monorepo
# Boundary UI Monorepo
![](boundary.png)
![Validate Monorepo](https://github.com/hashicorp/boundary-ui/workflows/Validate%20Monorepo/badge.svg)
This monorepo contains multiple projects, including UIs and addons, used by
Threshold (the admin web UI and the desktop client).
## About this fork
This repository is a community fork of
[hashicorp/boundary-ui](https://github.com/hashicorp/boundary-ui), rebranded
for the Threshold project (a community fork of Boundary CE). It is licensed
under the upstream Business Source License 1.1 (see [LICENSE](LICENSE) and
[NOTICE](NOTICE)) and is **not affiliated with, endorsed by, or sponsored by
HashiCorp or IBM**.
What changed relative to upstream:
- User-visible product name is Threshold (window titles, menus, about dialog,
installer/package names, app id `net.anhonesthost.cybercove.threshold`).
API paths, field names, protocol strings and environment variable names are
unchanged for compatibility with the server. The desktop client's persisted
settings are copied from the former "Boundary" user-data directory on first
launch.
- The desktop client looks for a `threshold` CLI first, then `boundary`.
- HashiCorp/IBM logos and brand art were removed and replaced with plain
placeholder marks.
- Nothing contacts HashiCorp services by default. The in-app updater, the
"unsupported controller" release-metadata lookup, and the CLI bundling
download are disabled until you configure your own hosts:
`THRESHOLD_UPDATE_FEED_URL` (desktop build, updater feed),
`THRESHOLD_RELEASES_METADATA_URL` / `THRESHOLD_RELEASES_PAGE_URL`
(desktop build, release links) and `THRESHOLD_CLI_RELEASES_URL` /
`THRESHOLD_CLI_ARCHIVE_PREFIX` (used with `SETUP_CLI=true` to bundle a CLI).
- Documentation links still point at the upstream Boundary documentation,
which is user-initiated only.
- Upstream HashiCorp-internal GitHub workflows and release metadata were
removed; CI lives in `.gitea/workflows/ci.yml`.
Upstream history, CHANGELOGs and copyright headers are preserved.
Boundary.
This top-level repository provides limited common tasks, such as installation
and commit assistance. However, most tasks must be executed from within a
+14
View File
@@ -0,0 +1,14 @@
# unconventional js
/blueprints/*/files/
# compiled output
/declarations/
/dist/
# misc
/coverage/
!.*
.*/
# ember-try
/.node_modules.ember-try/
+69
View File
@@ -0,0 +1,69 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
'use strict';
module.exports = {
root: true,
parser: '@babel/eslint-parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
// This is specific babel-config. If grows consider creating a babel config file
requireConfigFile: false,
babelOptions: {
plugins: [
['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: true }],
],
},
// end of babel-config
},
plugins: ['ember'],
extends: ['eslint:recommended', 'plugin:ember/recommended', 'prettier'],
env: {
browser: true,
},
rules: {
curly: ['error', 'multi-line', 'consistent'],
'ember/no-get': 'off',
'ember/no-get-with-default': 'off',
'ember/no-computed-properties-in-native-classes': 'off',
'ember/no-assignment-of-untracked-properties-used-in-tracking-contexts':
'off',
},
overrides: [
// node files
{
files: [
'./.eslintrc.js',
'./.prettierrc.js',
'./.template-lintrc.js',
'./ember-cli-build.js',
'./index.js',
'./testem.js',
'./blueprints/*/index.js',
'./config/**/*.js',
'./tests/dummy/config/**/*.js',
'./broccoli-plugins/**/*.js',
],
parserOptions: {
sourceType: 'script',
},
env: {
browser: false,
node: true,
},
extends: ['plugin:n/recommended'],
},
{
// test files
files: ['tests/**/*-test.{js,ts}'],
extends: ['plugin:qunit/recommended'],
rules: {
'qunit/require-expect': [2, 'except-simple'],
},
},
],
};
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+5 -38
View File
@@ -21,50 +21,17 @@ This addon contains the API data access layer for Boundary.
## Add API to an App
Add this addon to an Ember application's `devDependencies` as:
`"api": "workspace:*"`, for applications included in this monorepo.
`"api": "workspace:*"`, for applications included in this monorepo.
This addon also includes Mirage mocks. To include the `miragejs` dependency and this addon's mirage handlers configure the consuming app's `config/environment.js`
Since this addon also includes Mirage mocks, be sure to install
`ember-cli-mirage` and add the following config to your UI project:
```js
mirage: {
enabled: true
'ember-cli-mirage': {
directory: '../../addons/api/mirage'
}
```
Include `miragejs` and any api addon `peerDependencies` used by the mirage as dev dependencies in the consuming app,
eg: `@faker-js/faker`, otherwise mirage handler code might fail with an error.
To have mirage start and intercept requests when the application starts:
1. Add the `@embroider/macros` dependency to your application
2. Configure `@embroider/macros` with `startMirageWithApp` based on app's config within `ember-cli-build.js`:
```js
// ember-cli-build.js
module.exports = async function (defaults) {
// load the app's config
const { EMBER_ENV } = process.env;
var config = require('./config/environment')(EMBER_ENV);
const app = new EmberApp(defaults, {
'@embroider/macros': {
setOwnConfig: {
startMirageWithApp: config.mirage?.enabled ?? false
},
},
});
}
```
3. Finally, use the `@embroider/macros` config value for `startMirageWithApp` in `app/app.js` to conditionally start mirage:
```js
import { macroCondition, importSync, getOwnConfig, isTesting } from '@embroider/macros';
if (macroCondition(getOwnConfig().startMirageWithApp && !isTesting())) {
const startServer = importSync('[name of host app]/mirage/config').default;
startServer({});
}
```
## Installation
See monorepo README for installation instructions.
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -11,7 +11,7 @@ import { underscore } from '@ember/string';
/**
* This test helper can be used to help setup your sinon stubs in your tests.
* Must be called after setupMirage and setupDesktopContextBridgeApiMock in tests.
* Must be called after setupMirage.
*
* ```js
* import setupStubs from 'api/test-support/handlers/cache-daemon-search';
@@ -19,15 +19,14 @@ import { underscore } from '@ember/string';
* module('Acceptance | my test', function(hooks) {
* setupApplicationTest(hooks);
* setupMirage(hooks);
* setupDesktopContextBridgeApiMock(hooks);
* setupStubs(hooks);
*
* // add your actual tests here
* });
* ```
*
* This will setup a stub for window.desktop.daemon.searchCacheDaemon and include
* helper methods to help setup what the cache daemon search command returns.
* This will setup a stub for the IPC service and include helper methods to
* help setup what the cache daemon search command returns.
*
* @module Test Helpers
* @public
@@ -36,6 +35,9 @@ export default function setupStubs(hooks) {
let stubTypes = [];
hooks.beforeEach(function () {
const ipcService = this.owner.lookup('service:ipc');
this.ipcStub = sinon.stub(ipcService, 'invoke');
/**
* We aim to still use mirage data when stubbing out the cache daemon
* search. However, the handler expects the search data to be raw JSON from
@@ -54,32 +56,34 @@ export default function setupStubs(hooks) {
stubTypes = types;
types.forEach((type, i) => {
this.searchCacheDaemonStub.onCall(i).callsFake(() => {
let models;
let resourceName;
if (typeOf(type) === 'object') {
models = type.func();
resourceName = type.resource;
} else {
models = this.server.schema[type].all().models;
resourceName = type;
}
this.ipcStub
.withArgs('searchCacheDaemon')
.onCall(i)
.callsFake(() => {
let models;
let resourceName;
if (typeOf(type) === 'object') {
models = type.func();
resourceName = type.resource;
} else {
models = this.server.schema[type].all().models;
resourceName = type;
}
return {
[underscore(resourceNames[singularize(resourceName)])]: models.map(
(model) => {
// Use internal serializer to serialize the model correctly
// according to our mirage serializers
const modelData =
this.server.serializerOrRegistry.serialize(model);
return {
[underscore(resourceNames[singularize(resourceName)])]:
models.map((model) => {
// Use internal serializer to serialize the model correctly
// according to our mirage serializers
const modelData =
this.server.serializerOrRegistry.serialize(model);
// Serialize the data properly to standard JSON as that is what
// we're expecting from the cache daemon response
return JSON.parse(JSON.stringify(modelData));
},
),
};
});
// Serialize the data properly to standard JSON as that is what
// we're expecting from the cache daemon response
return JSON.parse(JSON.stringify(modelData));
}),
};
});
});
};
});
@@ -87,19 +91,22 @@ export default function setupStubs(hooks) {
hooks.afterEach(function () {
// Verify the number of mocks we set up match with how
// many times the cache daemon was called with
sinon.assert.callCount(this.searchCacheDaemonStub, stubTypes.length);
sinon.assert.callCount(
this.ipcStub.withArgs('searchCacheDaemon'),
stubTypes.length,
);
stubTypes.forEach((type, i) => {
// Assert that the stub was called with the resource we're trying to mock
// so we don't mistakenly mock the wrong resource
const call = this.searchCacheDaemonStub.getCall(i);
const ipcCall = this.ipcStub.withArgs('searchCacheDaemon').getCall(i);
let resource = type;
if (typeOf(type) === 'object') {
resource = type.resource;
}
const mappedResourceName = resourceNames[singularize(resource)];
sinon.assert.match(call.args[0], { resource: mappedResourceName });
sinon.assert.match(ipcCall.args[1], { resource: mappedResourceName });
});
sinon.restore();
@@ -1,34 +0,0 @@
/**
* Copyright IBM Corp. 2021, 2026
* SPDX-License-Identifier: BUSL-1.1
*/
import { settled } from '@ember/test-helpers';
export function createSetupMirage(startMirage) {
return function setupMirage(hooks) {
hooks.beforeEach(function () {
if (!this.owner) {
throw new Error(
'Must call one of the ember-qunit setupTest() / setupRenderingTest() / setupApplicationTest() first',
);
}
// the environment property here is configuration to the mirage server:
// https://github.com/miragejs/miragejs/blob/7ff4f3f6fe56bf0cb1648f5af3f5210fcb07e20b/types/index.d.ts#L383
// It is not related to ember's build environment. In this case for mirage the "test" environment does
// not load the default scenario:
// https://github.com/miragejs/miragejs/blob/7ff4f3f6fe56bf0cb1648f5af3f5210fcb07e20b/lib/server.js#L302
this.server = startMirage({ environment: 'test' });
});
hooks.afterEach(function () {
return settled().then(() => {
if (this.server) {
this.server.shutdown();
delete this.server;
}
});
});
};
}
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+3 -3
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -16,7 +16,7 @@ class InvalidRolePrincipalTypeError extends Error {
export default class RoleAbility extends ModelAbility {
// =services
@service abilities;
@service can;
// =permissions
@@ -64,6 +64,6 @@ export default class RoleAbility extends ModelAbility {
`Expected a role principal of type 'user', 'group', or 'managed-group'. Got '${type}'.`,
);
}
return this.abilities.can(`read ${type}`, this.model);
return this.can.can(`read ${type}`, this.model);
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+5 -37
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -131,34 +131,11 @@ export default class ApplicationAdapter extends RESTAdapter.extend(
// which indicates that there are more items in the list
// or the batch size has not been reached
do {
try {
result = await super.query(store, schema, queryObject);
} catch (e) {
// If we hit a rate limit mid-pagination, return whatever
// data has been accumulated so far rather than throwing and leaving
// the user stuck with nothing to show.
// Without a list_token this is the very first request with nothing to
// show, so rethrow and let normal error handling apply.
if (e?.errors?.[0]?.isRateLimited && queryObject.list_token) {
result ??= {};
result.items = data;
result.response_type = 'complete';
result.meta = {
...result.meta,
rateLimitWarning: { retryAfter: e.errors[0].retryAfter },
};
return prenormalizeArrayResponse(result);
}
// For all other errors (or a 429 on the very first request with
// no data yet), rethrow so normal error handling applies.
throw e;
}
// Add the result items to a data array
result = await super.query(store, schema, queryObject);
//add the result items to a data array
if (result && result.items) {
data.push(...result.items);
// Pass in the list token for subsequent calls to fetch the remaining list items
//pass in the list token for subsequent calls to fetch the remaining list items
queryObject.list_token = result.list_token;
}
} while (
@@ -260,7 +237,6 @@ export default class ApplicationAdapter extends RESTAdapter.extend(
* - `403 isForbidden`: the session is authenticated but does not have
* permission to perform the requested action
* - `404 isNotFound`: the requested resource could not be found
* - `429 isRateLimited`: the client has exceeded the rate limit
* - `500 isServer`: an internal server error occurred
* - `isUnknown`: an error occurred, but we don't know which or
* we don't distinguish it yet
@@ -272,7 +248,7 @@ export default class ApplicationAdapter extends RESTAdapter.extend(
* @param {Object} payload
* @return {Array} errors payload
*/
normalizeErrorResponse(status, headers /*, payload*/) {
normalizeErrorResponse(/*status, headers, payload*/) {
const errors = super.normalizeErrorResponse(...arguments);
if (isArray(errors)) {
errors.forEach((error) => {
@@ -286,14 +262,6 @@ export default class ApplicationAdapter extends RESTAdapter.extend(
case 404:
error.isNotFound = true;
break;
case 429:
error.isRateLimited = true;
// Attach rate-limit metadata from response headers so downstream
// error handlers can inform the user when they may retry.
error.retryAfter = Number(
headers['Retry-After'] ?? headers['retry-after'],
);
break;
case 500:
error.isServer = true;
break;
+2 -2
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -23,7 +23,7 @@ export default class HostCatalogAdapter extends ApplicationAdapter {
try {
const pluginName = snapshot.attr('plugin')?.name;
if (pluginName) url = `${url}?plugin_name=${pluginName}`;
} catch {
} catch (e) {
// Ignore any adapter errors here
}
}
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -23,7 +23,7 @@ export default class SessionRecordingAdapter extends ApplicationAdapter {
let method;
try {
method = snapshot?.adapterOptions?.method;
} catch {
} catch (e) {
// Ignore any adapter errors here
}
if (method === 'download') {
+2 -2
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -22,7 +22,7 @@ export default class StorageBucketAdapter extends ApplicationAdapter {
let pluginName;
try {
pluginName = snapshot?.attr('plugin')?.name;
} catch {
} catch (e) {
// Ignore any adapter errors here
}
if (requestType === 'createRecord' && pluginName) {
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -72,7 +72,7 @@ export default class GeneratedHostCatalogModel extends BaseModel {
@attr('string', {
for: {
type: 'plugin',
name: ['aws', 'azure', 'gcp'],
name: ['aws', 'gcp'],
},
description:
'An expression used to filter the workers that have network access to a service that is hosting the external object store.',
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -96,34 +96,6 @@ export default class GeneratedSessionRecordingModel extends BaseModel {
})
duration;
@attr({
description:
'The detailed state of the session recording. This contains storage_state, syncing_error_details, and verification_error_details.',
readOnly: true,
})
recording_state;
@attr('string', {
description:
'The availability of the session recording. One of "available" or "not available".',
readOnly: true,
})
availability;
@attr('date', {
description: 'The time until a session recording is required to be stored.',
readOnly: true,
})
retain_until;
@attr('date', {
description:
'The time a session recording is scheduled to be automatically deleted.',
readOnly: true,
})
delete_after;
// Deprecated: These two fields should be removed once support for RDP is added.
@attr('string', {
description:
'The current state of the session recording. One of "started", "available" and "unknown".',
@@ -137,4 +109,17 @@ export default class GeneratedSessionRecordingModel extends BaseModel {
readOnly: true,
})
error_details;
@attr('date', {
description: 'The time until a session recording is required to be stored.',
readOnly: true,
})
retain_until;
@attr('date', {
description:
'The time a session recording is scheduled to be automatically deleted.',
readOnly: true,
})
delete_after;
}
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -59,6 +59,7 @@ const fetchControllerData = async (context, next) => {
*/
export default class CacheDaemonHandler {
@service session;
@service ipc;
constructor(context) {
setOwner(this, getOwner(context));
@@ -69,8 +70,9 @@ export default class CacheDaemonHandler {
case 'query': {
const { store, data } = context.request;
const { type, query, options: { pushToStore = true } = {} } = data;
const isCacheDaemonRunning =
await window.desktop.daemon.isCacheDaemonRunning();
const isCacheDaemonRunning = await this.ipc.invoke(
'isCacheDaemonRunning',
);
// eslint-disable-next-line no-unused-vars
let { recursive, scope_id, page, pageSize, ...remainingQuery } = query;
@@ -99,14 +101,6 @@ export default class CacheDaemonHandler {
const token = sessionData?.token;
const resourceName = resourceNames[type];
if (remainingQuery.query?.sort) {
const { attribute, direction } = remainingQuery.query.sort;
if (attribute && direction) {
remainingQuery.sort_by = attribute;
remainingQuery.sort_direction = direction;
}
}
remainingQuery = {
...remainingQuery,
query: searchQuery,
@@ -117,19 +111,23 @@ export default class CacheDaemonHandler {
let cacheDaemonResults = {};
try {
cacheDaemonResults =
await window.desktop.daemon.searchCacheDaemon(remainingQuery);
cacheDaemonResults = await this.ipc.invoke(
'searchCacheDaemon',
remainingQuery,
);
} catch (e) {
// If we got a 403, most likely the cache daemon was restarted and our token is no longer valid
// I'm not sure if we can get a 401 since we always send a token but we'll handle it in the same way
if (e.statusCode === 403 || e.statusCode === 401) {
try {
await window.desktop.daemon.addTokenToDaemons({
await this.ipc.invoke('addTokenToDaemons', {
tokenId: auth_token_id,
token,
});
cacheDaemonResults =
await window.desktop.daemon.searchCacheDaemon(remainingQuery);
cacheDaemonResults = await this.ipc.invoke(
'searchCacheDaemon',
remainingQuery,
);
} catch (err) {
// If it fails again just fall back to fetching controller data
__electronLog?.error(
+10 -44
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -59,39 +59,17 @@ export default class SqliteHandler {
let payload,
listToken,
writeToDbPromise,
totalInsert = 0,
rateLimitWarning;
totalInsert = 0;
if (!peekDb) {
let tokenKey = `${type}-${hashCode(remainingQuery)}`;
// The global token key represents a recursive query from global scope,
// which pulls back every resource of this type.
const globalTokenKey = `${type}-${hashCode({ scope_id: 'global', recursive: true })}`;
const tokenKey = `${type}-${hashCode(remainingQuery)}`;
if (storeToken) {
// Always prefer the global token when it exists for
// any more fine-grained query. The global query already fetched every
// item for this resource type, so we should just re-use it.
if (tokenKey !== globalTokenKey) {
const [globalTokenObj] = await this.sqlite.fetchResource({
...generateSQLExpressions('token', {
filters: { id: [{ equals: globalTokenKey }] },
}),
});
if (globalTokenObj?.token) {
tokenKey = globalTokenKey;
listToken = globalTokenObj.token;
}
}
// Only look up the specific token if no global token was found.
if (!listToken) {
const [tokenObj] = await this.sqlite.fetchResource({
...generateSQLExpressions('token', {
filters: { id: [{ equals: tokenKey }] },
}),
});
listToken = tokenObj?.token;
}
const [tokenObj] = await this.sqlite.fetchResource({
...generateSQLExpressions('token', {
filters: { id: [{ equals: tokenKey }] },
}),
});
listToken = tokenObj?.token;
} else {
// This is a temporary fix of clearing the DB (specifically for auth-methods)
// since we are not storing the token we do not get back a list of removed_ids
@@ -108,11 +86,6 @@ export default class SqliteHandler {
});
totalInsert += payload.items?.length ?? 0;
// Propagate any rate-limit warning the adapter attached
if (payload.meta?.rateLimitWarning) {
rateLimitWarning = payload.meta.rateLimitWarning;
}
// await the previous writeToDbPromise before writing to db again
if (writeToDbPromise) {
await writeToDbPromise;
@@ -190,14 +163,7 @@ export default class SqliteHandler {
// This isn't conventional but is better than returning an ArrayProxy
// or EmberArray since the ember store query method asserts it has to be an array
// so we can't just return an object.
records.meta = {
totalItems: count[0].total,
};
if (rateLimitWarning) {
records.meta.rateLimitWarning = rateLimitWarning;
}
records.meta = { totalItems: count[0].total };
return records;
}
default:
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2021, 2026
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
Loaded 100 of 2336 files, more files were not shown because too many files have changed in this diff. Show more