Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec698d5672 | ||
|
|
266f10d1eb | ||
|
|
e30168c55a | ||
|
|
4e7d6ba57e | ||
|
|
f3968d353d | ||
|
|
33055d6095 | ||
|
|
f48e6dc049 | ||
|
|
605b7940e3 | ||
|
|
7454ecf57a | ||
|
|
28b185bec8 | ||
|
|
e345946c7d | ||
|
|
6c3a57b599 | ||
|
|
52e36e6463 | ||
|
|
392e49bf49 | ||
|
|
eba17d3c71 | ||
|
|
cdfeee3916 | ||
|
|
f59603d70a | ||
|
|
638dbff235 | ||
|
|
e310b5abfa | ||
|
|
b63ea6eee0 | ||
|
|
780740f2f2 | ||
|
|
163758a1cb | ||
|
|
e91bf99f6d | ||
|
|
43c9389b69 | ||
|
|
79b6360c30 | ||
|
|
93d709f7ba | ||
|
|
999c21c66a | ||
|
|
d6e8e58ca1 | ||
|
|
df24ba6a15 | ||
|
|
b1b49edb39 | ||
|
|
aaabfbe54d | ||
|
|
51ee5b2b20 | ||
|
|
566a02cbeb | ||
|
|
3a847605ed | ||
|
|
772857dbad | ||
|
|
9e069ffc0c | ||
|
|
ba77e9dd1b | ||
|
|
ea1e7a99de | ||
|
|
46ededd676 | ||
|
|
b2b42cafd4 | ||
|
|
b6154cb1f7 | ||
|
|
ebe5ae5f19 | ||
|
|
f8af37db43 | ||
|
|
4de3b5a61f | ||
|
|
3829301c24 | ||
|
|
e68e17c5d4 | ||
|
|
63b810d53f | ||
|
|
72fa6d86c4 | ||
|
|
1780077068 | ||
|
|
1e49283a33 | ||
|
|
6f7138be46 | ||
|
|
709d6e0be8 | ||
|
|
3ba93927fe | ||
|
|
733c4c546c | ||
|
|
99713ea0e1 | ||
|
|
b493285ee1 | ||
|
|
3e88411998 | ||
|
|
55e1e68f30 | ||
|
|
055da3d958 | ||
|
|
bd9b094834 | ||
|
|
773c1596e5 | ||
|
|
1d0941865b | ||
|
|
ecdf9c5b42 | ||
|
|
89f94a9d07 | ||
|
|
0b7e3fcad1 | ||
|
|
4170c7aa24 | ||
|
|
c8737f0474 | ||
|
|
43249169d8 | ||
|
|
ab2c235c52 | ||
|
|
d45548e612 | ||
|
|
f1ffb80b80 | ||
|
|
9204c63b17 | ||
|
|
b5d33948dc | ||
|
|
29fb5b00cb | ||
|
|
f3a124cc47 | ||
|
|
2766be2c2e | ||
|
|
b9d064c949 | ||
|
|
0bac7d2711 | ||
|
|
1d08ddb513 | ||
|
|
824427b690 | ||
|
|
183bde311c | ||
|
|
30c2cab0b7 | ||
|
|
6fcc743217 | ||
|
|
719bab7358 | ||
|
|
95f72e1248 | ||
|
|
f9a9f677ca | ||
|
|
dd0c5df25c | ||
|
|
4fc3244049 | ||
|
|
5faf830d46 | ||
|
|
d2cf82b85c | ||
|
|
fb0020c395 | ||
|
|
e55ea0b629 | ||
|
|
9234dbae70 | ||
|
|
27136eaa71 | ||
|
|
6554af1164 | ||
|
|
437d0e686d | ||
|
|
25b801826d | ||
|
|
123818dc70 | ||
|
|
dafcd046d7 | ||
|
|
accf9faf60 | ||
|
|
6bb237e78c | ||
|
|
bbb5808875 | ||
|
|
905a8f1951 | ||
|
|
f39961bbf5 | ||
|
|
2bf09011fb | ||
|
|
013aa2e570 | ||
|
|
953e35bcd6 | ||
|
|
e138b06fd3 | ||
|
|
2ef6b0549d | ||
|
|
1c49303432 | ||
|
|
f31b1e975d | ||
|
|
48d0087141 | ||
|
|
58cc9e56fc | ||
|
|
189a453e8b | ||
|
|
6fca90747c | ||
|
|
92f5a65c00 | ||
|
|
d8744e81bc | ||
|
|
136baf8260 | ||
|
|
ef47c163d0 | ||
|
|
39e5e3406b | ||
|
|
91d8d61afb | ||
|
|
b1d9153efe | ||
|
|
fda1f56ad1 | ||
|
|
fa18bfff01 | ||
|
|
72f7c8a92d | ||
|
|
838bc37243 | ||
|
|
866972c6c6 | ||
|
|
b19d76f249 | ||
|
|
35ccaeba56 | ||
|
|
bf134072e5 | ||
|
|
0bd152e0b5 | ||
|
|
928ca5409c | ||
|
|
0f846eab2c | ||
|
|
14ed74dd3d | ||
|
|
701d19bd18 | ||
|
|
240a544d82 | ||
|
|
b4f3741979 | ||
|
|
396bf0a43f | ||
|
|
3225ccda10 | ||
|
|
ad2c1ba2ad | ||
|
|
ea591df0bb | ||
|
|
72639bd6a3 | ||
|
|
31f0044c0f | ||
|
|
d0924f7e6d | ||
|
|
d2616acf36 | ||
|
|
dfd116bd56 | ||
|
|
830acef847 | ||
|
|
ee7c916494 | ||
|
|
46d477ea5b | ||
|
|
177b4af695 | ||
|
|
d2b8805605 | ||
|
|
39dedc68ec | ||
|
|
bd67756cda | ||
|
|
dd37fa4270 | ||
|
|
3c5c048152 | ||
|
|
dd6e4ef2d0 | ||
|
|
bce79f3488 | ||
|
|
74793a2399 | ||
|
|
6b120b053a | ||
|
|
1d0d62337e | ||
|
|
df8bfc42bb | ||
|
|
ff087738fc | ||
|
|
27567c88c9 | ||
|
|
9077a747d6 | ||
|
|
b359d9f525 | ||
|
|
ad7bd2e52d | ||
|
|
36aed9588b | ||
|
|
f8c81a29c4 | ||
|
|
c91771e152 | ||
|
|
3b7873302b | ||
|
|
d79bd54f0b | ||
|
|
51dc9a0e49 | ||
|
|
b49e55d400 | ||
|
|
33cb7e0a50 | ||
|
|
9edc90306e | ||
|
|
0a75e05b28 | ||
|
|
4a179ac3e3 | ||
|
|
42e32f9568 | ||
|
|
0223755b2a | ||
|
|
30a5f2a701 | ||
|
|
d2d351c9f7 | ||
|
|
e1696e9a4d | ||
|
|
25f015b179 | ||
|
|
9e263379a7 | ||
|
|
4c7ea161cd | ||
|
|
dc026c44a1 | ||
|
|
cb8b21c10c | ||
|
|
47c1beadcd | ||
|
|
8f7eb2abea | ||
|
|
c2b0f321de | ||
|
|
ba7b8b8824 | ||
|
|
9e612cf83d | ||
|
|
2154251c30 | ||
|
|
2d38266609 | ||
|
|
d414df4ca4 | ||
|
|
eab93cf6c5 | ||
|
|
3304def44a | ||
|
|
a4bf02b21b | ||
|
|
e0982da744 | ||
|
|
8abed1a809 | ||
|
|
a9a6518b23 | ||
|
|
1bafbe1ad2 | ||
|
|
a26074a3b8 | ||
|
|
90fd2f1447 | ||
|
|
e59690e703 | ||
|
|
bf06e9f654 | ||
|
|
84359d8e79 | ||
|
|
7801429530 | ||
|
|
dc9376a460 | ||
|
|
1f4076d8d4 | ||
|
|
f202d0f533 | ||
|
|
4344dcbb36 | ||
|
|
87d6bbae2a | ||
|
|
7a42bf456e | ||
|
|
a51f1eee8e | ||
|
|
5b72a916e4 | ||
|
|
42013a919f | ||
|
|
3918f82e14 | ||
|
|
6e79a2a133 | ||
|
|
088deaed3a | ||
|
|
7504e7710c | ||
|
|
bb7352ca54 | ||
|
|
b42ecbff36 | ||
|
|
5fd9f0216a | ||
|
|
942ea99459 | ||
|
|
990e2d6b9d | ||
|
|
f776ba0617 | ||
|
|
fb57965457 | ||
|
|
b99fce7d55 | ||
|
|
0a2d743ea2 | ||
|
|
fbd613084d | ||
|
|
4cd56f8ae5 | ||
|
|
c0d41c0a62 | ||
|
|
389c635030 | ||
|
|
d93a0c170c | ||
|
|
aa18f599ce | ||
|
|
aa7eb2e844 |
No files matched your search
+4
-4
@@ -2,20 +2,20 @@ schema_version = 1
|
|||||||
|
|
||||||
project {
|
project {
|
||||||
license = "BUSL-1.1"
|
license = "BUSL-1.1"
|
||||||
copyright_year = 2024
|
copyright_year = 2021
|
||||||
|
|
||||||
# (OPTIONAL) A list of globs that should not have copyright/license headers.
|
# (OPTIONAL) A list of globs that should not have copyright/license headers.
|
||||||
# Supports doublestar glob patterns for more flexibility in defining which
|
# Supports doublestar glob patterns for more flexibility in defining which
|
||||||
# files or folders should be ignored
|
# files or folders should be ignored
|
||||||
header_ignore = [
|
header_ignore = [
|
||||||
".github/**",
|
|
||||||
".husky/**",
|
".husky/**",
|
||||||
"**/node_modules/**",
|
"**/node_modules/**",
|
||||||
"**/dist/**",
|
"**/dist/**",
|
||||||
"**/coverage/**",
|
"**/coverage/**",
|
||||||
"ui/desktop/electron-app/out/**",
|
|
||||||
"ui/desktop/electron-app/ember-dist/**",
|
|
||||||
"**/pnpm-lock.yaml",
|
"**/pnpm-lock.yaml",
|
||||||
"**/pnpm-workspace.yaml",
|
"**/pnpm-workspace.yaml",
|
||||||
|
"ui/desktop/electron-app/out/**",
|
||||||
|
"ui/desktop/electron-app/ember-dist/**",
|
||||||
|
"e2e-tests/api-client/**"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) HashiCorp, Inc.
|
# Copyright IBM Corp. 2021, 2026
|
||||||
# SPDX-License-Identifier: BUSL-1.1
|
# SPDX-License-Identifier: BUSL-1.1
|
||||||
|
|
||||||
contact_links:
|
contact_links:
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) HashiCorp, Inc.
|
# Copyright IBM Corp. 2021, 2026
|
||||||
# SPDX-License-Identifier: BUSL-1.1
|
# SPDX-License-Identifier: BUSL-1.1
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
|
|||||||
@@ -12,12 +12,17 @@
|
|||||||
## Checklist
|
## Checklist
|
||||||
<!-- strikethrough the checklist item that is not relevant to your change -->
|
<!-- 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 before and after screenshots for UI changes
|
||||||
- [ ] I have added JSON response output for API 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 added steps to reproduce and test for bug fixes in the description
|
||||||
- [ ] I have commented on my code, particularly in hard-to-understand areas
|
- [ ] I have commented on my code, particularly in hard-to-understand areas
|
||||||
- [ ] My changes generate no new warnings
|
- [ ] My changes generate no new warnings
|
||||||
- [ ] I have added tests that prove my fix is effective or that my feature works
|
- [ ] 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
|
## PCI review checklist
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Copyright (c) HashiCorp, Inc.
|
# Copyright IBM Corp. 2021, 2026
|
||||||
# SPDX-License-Identifier: BUSL-1.1
|
# SPDX-License-Identifier: BUSL-1.1
|
||||||
|
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# Configure Git
|
# Configure Git
|
||||||
@@ -91,4 +92,4 @@ gh pr create \
|
|||||||
-b "${BASE_BRANCH/oss\//} upstream merge of (${SHA::7})"
|
-b "${BASE_BRANCH/oss\//} upstream merge of (${SHA::7})"
|
||||||
gh pr merge --auto --merge
|
gh pr merge --auto --merge
|
||||||
|
|
||||||
# This PR will be need to be approved manually
|
# This PR will be need to be approved manually
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
name: A11y Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [labeled, opened, synchronize, reopened]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
a11y-test:
|
||||||
|
name: Run A11y Tests
|
||||||
|
if: contains(github.event.pull_request.labels.*.name, 'a11y-tests')
|
||||||
|
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||||
|
timeout-minutes: 40
|
||||||
|
steps:
|
||||||
|
- uses: browser-actions/setup-chrome@4f8e94349a351df0f048634f25fec36c3c91eded # v2.1.1
|
||||||
|
with:
|
||||||
|
install-dependencies: true
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||||
|
with:
|
||||||
|
run_install: false
|
||||||
|
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.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
|
||||||
@@ -11,11 +11,11 @@ jobs:
|
|||||||
name: Install dependencies
|
name: Install dependencies
|
||||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda #v4.1.0
|
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||||
with:
|
with:
|
||||||
run_install: false
|
run_install: false
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
@@ -26,12 +26,12 @@ jobs:
|
|||||||
needs: [dependencies]
|
needs: [dependencies]
|
||||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda #v4.1.0
|
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||||
with:
|
with:
|
||||||
run_install: false
|
run_install: false
|
||||||
- name: Build
|
- name: Build
|
||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
@@ -39,12 +39,12 @@ jobs:
|
|||||||
- run: pnpm install --offline
|
- run: pnpm install --offline
|
||||||
- run: pnpm run build:ui:admin:oss
|
- run: pnpm run build:ui:admin:oss
|
||||||
- name: Upload artifact admin-ui
|
- name: Upload artifact admin-ui
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
with:
|
with:
|
||||||
name: admin-ui
|
name: admin-ui
|
||||||
path: ./ui/admin/dist/
|
path: ./ui/admin/dist/
|
||||||
- name: Upload artifact OSS admin UI
|
- name: Upload artifact OSS admin UI
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
with:
|
with:
|
||||||
name: admin-ui-oss
|
name: admin-ui-oss
|
||||||
path: ./ui/admin/dist/
|
path: ./ui/admin/dist/
|
||||||
@@ -53,12 +53,12 @@ jobs:
|
|||||||
needs: [dependencies]
|
needs: [dependencies]
|
||||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda #v4.1.0
|
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||||
with:
|
with:
|
||||||
run_install: false
|
run_install: false
|
||||||
- name: Build
|
- name: Build
|
||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
@@ -66,7 +66,7 @@ jobs:
|
|||||||
- run: pnpm install --offline
|
- run: pnpm install --offline
|
||||||
- run: pnpm run build:ui:admin:enterprise
|
- run: pnpm run build:ui:admin:enterprise
|
||||||
- name: Upload artifact enterprise admin UI
|
- name: Upload artifact enterprise admin UI
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
with:
|
with:
|
||||||
name: admin-ui-ent
|
name: admin-ui-ent
|
||||||
path: ./ui/admin/dist/
|
path: ./ui/admin/dist/
|
||||||
@@ -75,12 +75,12 @@ jobs:
|
|||||||
needs: [dependencies]
|
needs: [dependencies]
|
||||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda #v4.1.0
|
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||||
with:
|
with:
|
||||||
run_install: false
|
run_install: false
|
||||||
- name: Build
|
- name: Build
|
||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
@@ -88,7 +88,7 @@ jobs:
|
|||||||
- run: pnpm install --offline
|
- run: pnpm install --offline
|
||||||
- run: pnpm run build:ui:admin:hcp
|
- run: pnpm run build:ui:admin:hcp
|
||||||
- name: Upload artifact HCP admin UI
|
- name: Upload artifact HCP admin UI
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
with:
|
with:
|
||||||
name: admin-ui-hcp
|
name: admin-ui-hcp
|
||||||
path: ./ui/admin/dist/
|
path: ./ui/admin/dist/
|
||||||
@@ -30,7 +30,12 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
|
||||||
|
- name: Set up Node
|
||||||
|
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
|
|||||||
@@ -6,10 +6,14 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- 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
|
- uses: hashicorp/setup-copywrite@32638da2d4e81d56a0764aa1547882fc4d209636 # v1.1.3
|
||||||
- name: Add missing Copyright Headers
|
- name: Add missing Copyright Headers
|
||||||
run: copywrite headers
|
run: copywrite headers
|
||||||
- uses: stefanzweifel/git-auto-commit-action@778341af668090896ca464160c2def5d1d1a3eb0 # v6.0.1
|
- uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0
|
||||||
with:
|
with:
|
||||||
commit_message: Add missing copyright headers
|
commit_message: Add missing copyright headers
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
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}")"
|
|
||||||
@@ -6,6 +6,6 @@ jobs:
|
|||||||
triage:
|
triage:
|
||||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0
|
- uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1
|
||||||
with:
|
with:
|
||||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
@@ -6,11 +6,11 @@ jobs:
|
|||||||
name: Install dependencies
|
name: Install dependencies
|
||||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda #v4.1.0
|
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||||
with:
|
with:
|
||||||
run_install: false
|
run_install: false
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
@@ -22,11 +22,11 @@ jobs:
|
|||||||
needs: [dependencies]
|
needs: [dependencies]
|
||||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda #v4.1.0
|
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||||
with:
|
with:
|
||||||
run_install: false
|
run_install: false
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
@@ -40,11 +40,11 @@ jobs:
|
|||||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||||
timeout-minutes: 5
|
timeout-minutes: 5
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda #v4.1.0
|
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||||
with:
|
with:
|
||||||
run_install: false
|
run_install: false
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
@@ -58,14 +58,14 @@ jobs:
|
|||||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
steps:
|
steps:
|
||||||
- uses: browser-actions/setup-chrome@c785b87e244131f27c9f19c1a33e2ead956ab7ce # v1.7.3
|
- uses: browser-actions/setup-chrome@4f8e94349a351df0f048634f25fec36c3c91eded # v2.1.1
|
||||||
with:
|
with:
|
||||||
install-dependencies: true
|
install-dependencies: true
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda #v4.1.0
|
- uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||||
with:
|
with:
|
||||||
run_install: false
|
run_install: false
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ jobs:
|
|||||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
|
token: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
|
||||||
- run: |
|
- run: |
|
||||||
|
|||||||
@@ -0,0 +1,252 @@
|
|||||||
|
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
|
||||||
|
# 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 diffferences between
|
||||||
|
# the two repos
|
||||||
|
if: github.actor != 'hc-github-team-secure-boundary'
|
||||||
|
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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
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@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.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@5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85
|
||||||
|
|
||||||
|
- name: Set up Enos
|
||||||
|
uses: hashicorp/action-setup-enos@17b90fcf9591275b468a94aefb9dc6a93017de8a
|
||||||
|
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 node 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
|
||||||
|
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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.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
|
||||||
|
if [[ "${{ github.repository }}" == "hashicorp/boundary-ui" ]]; then
|
||||||
|
pnpm run ${{ matrix.test_command }} --reporter=html
|
||||||
|
elif [[ "${{ github.repository }}" == "hashicorp/boundary-ui-enterprise" ]]; then
|
||||||
|
# only run tests on chromium because playwright dependencies can't
|
||||||
|
# be installed to support other browsers
|
||||||
|
pnpm run ${{ matrix.test_command }} --project=chromium --reporter=html
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Upload Playwright report
|
||||||
|
if: ${{ failure() }}
|
||||||
|
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
|
with:
|
||||||
|
name: playwright-report-${{ matrix.boundary_edition }}
|
||||||
|
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@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 }}"
|
||||||
@@ -3,30 +3,49 @@ name: Test E2E Desktop Client
|
|||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [labeled, opened, synchronize, reopened]
|
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:
|
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:
|
jobs:
|
||||||
test:
|
test:
|
||||||
if: ${{contains(github.event.pull_request.labels.*.name, 'desktop')}}
|
name: test
|
||||||
name: Run Desktop E2E Tests
|
# don't need to run e2e tests on ce -> ent merges since tests were already
|
||||||
runs-on: ubuntu-22.04
|
# run in the ce branch, and there are currently no code diffferences between
|
||||||
|
# the two repos
|
||||||
|
if: github.actor != 'hc-github-team-secure-boundary'
|
||||||
|
runs-on: ${{ fromJSON(vars.RUNNER_UBUNTU_22) }}
|
||||||
env:
|
env:
|
||||||
ENOS_VAR_boundary_edition: "ent"
|
ENOS_VAR_boundary_edition: "ent"
|
||||||
ENOS_VAR_e2e_debug_no_run: true
|
ENOS_VAR_e2e_debug_no_run: true
|
||||||
ENOS_VAR_boundary_license_path: "./license.hclic"
|
|
||||||
SETUP_CLI: true
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up pnpm
|
- name: Set up pnpm
|
||||||
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda #v4.1.0
|
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 #v4.2.0
|
||||||
with:
|
with:
|
||||||
run_install: false
|
run_install: false
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
@@ -35,81 +54,137 @@ jobs:
|
|||||||
ui/desktop/electron-app/pnpm-lock.yaml
|
ui/desktop/electron-app/pnpm-lock.yaml
|
||||||
|
|
||||||
- name: Set up Terraform
|
- name: Set up Terraform
|
||||||
uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd
|
uses: hashicorp/setup-terraform@5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85
|
||||||
|
|
||||||
- name: Set up Enos
|
- name: Set up Enos
|
||||||
uses: hashicorp/action-setup-enos@b9fa53484a1e8fdcc7b02a118bcf01d65b9414c9
|
uses: hashicorp/action-setup-enos@17b90fcf9591275b468a94aefb9dc6a93017de8a
|
||||||
with:
|
with:
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Install Vault CLI
|
- name: Install Vault CLI
|
||||||
run: |
|
run: |
|
||||||
wget https://releases.hashicorp.com/vault/1.12.2/vault_1.12.2_linux_amd64.zip -O /tmp/vault.zip
|
wget https://releases.hashicorp.com/vault/1.17.6/vault_1.17.6_linux_amd64.zip -O /tmp/vault.zip
|
||||||
unzip /tmp/vault.zip -d /usr/local/bin
|
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
|
- name: Checkout boundary-enterprise
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
with:
|
with:
|
||||||
repository: hashicorp/boundary-enterprise
|
repository: hashicorp/boundary-enterprise
|
||||||
# ref: ${{ github.event.inputs.boundary-enterprise-branch }}
|
ref: ${{ github.event.inputs.boundary-enterprise-branch || 'main' }}
|
||||||
path: support/src/boundary-enterprise
|
path: support/src/boundary-enterprise
|
||||||
token: ${{ secrets.ELEVATED_GITHUB_TOKEN }}
|
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
|
- name: GH fix for localhost resolution
|
||||||
run: |
|
run: |
|
||||||
cat /etc/hosts && echo "-----------"
|
if [[ "${{ github.repository }}" == "hashicorp/boundary-ui" ]]; then
|
||||||
sudo sed -i 's/::1 *localhost ip6-localhost ip6-loopback/::1 ip6 -localhost ip6-loopback/g' /etc/hosts
|
cat /etc/hosts && echo "-----------"
|
||||||
cat /etc/hosts
|
sudo sed -i 's/::1 *localhost ip6-localhost ip6-loopback/::1 ip6 -localhost ip6-loopback/g' /etc/hosts
|
||||||
ssh -V
|
cat /etc/hosts
|
||||||
|
ssh -V
|
||||||
|
fi
|
||||||
|
|
||||||
echo "127.0.0.1 localhost boundary" | sudo tee -a /etc/hosts
|
- name: Set git config
|
||||||
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: |
|
run: |
|
||||||
docker pull hashicorp/boundary-enterprise:latest
|
git config --global url."https://oauth2:${{ secrets.ELEVATED_GITHUB_TOKEN }}@github.com".insteadOf "https://github.com"
|
||||||
docker save hashicorp/boundary-enterprise:latest | gzip > /tmp/boundary-enterprise.zip
|
|
||||||
|
- 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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
||||||
|
with:
|
||||||
|
go-version: ${{ steps.get-go-version.outputs.go-version }}
|
||||||
|
cache: false
|
||||||
|
|
||||||
# TODO: Set up license in a better way? Use directly rather than writing to file and pull from secrets manager
|
|
||||||
- name: Set up test infra
|
- name: Set up test infra
|
||||||
id: infra
|
id: infra
|
||||||
run: |
|
run: |
|
||||||
echo "${{ secrets.BOUNDARY_ENT_LICENSE }}" > ./support/src/boundary-enterprise/enos/license.hclic
|
|
||||||
ssh-keygen -N '' -t ed25519 -f ~/.ssh/github_enos
|
ssh-keygen -N '' -t ed25519 -f ~/.ssh/github_enos
|
||||||
mkdir -p ./enos/terraform-plugin-cache
|
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_enos_user=$GITHUB_ACTOR && \
|
||||||
export ENOS_VAR_aws_ssh_private_key_path=~/.ssh/github_enos && \
|
export ENOS_VAR_aws_ssh_private_key_path=~/.ssh/github_enos && \
|
||||||
export ENOS_VAR_boundary_docker_image_name=hashicorp/boundary-enterprise:latest && \
|
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:local
|
||||||
enos scenario launch --timeout 60m0s --chdir ./support/src/boundary-enterprise/enos e2e_ui_docker_ent builder:crt
|
|
||||||
|
- 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
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
pnpm install --frozen-lockfile
|
pnpm install --frozen-lockfile
|
||||||
cd e2e-tests
|
cd e2e-tests
|
||||||
pnpm playwright install --with-deps
|
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
|
# Runner is headless so we need to enable a display to run the client
|
||||||
- name: Run Tests
|
- name: Run Tests
|
||||||
run: |
|
run: |
|
||||||
source <(bash ./support/src/boundary-enterprise/enos/scripts/test_e2e_env.sh)
|
source <(bash ./support/src/boundary-enterprise/enos/scripts/test_e2e_env.sh)
|
||||||
cd e2e-tests
|
cd e2e-tests
|
||||||
|
|
||||||
export DISPLAY=:99
|
export DISPLAY=:99
|
||||||
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
|
Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
|
||||||
pnpm run desktop
|
pnpm run desktop
|
||||||
|
|
||||||
- name: Upload Playwright report
|
- name: Upload Playwright report
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||||
with:
|
with:
|
||||||
name: playwright-report
|
name: playwright-report
|
||||||
path: e2e-tests/playwright-report
|
path: e2e-tests/playwright-report
|
||||||
|
|
||||||
- name: Clean up test infra
|
- name: Clean up test infra
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
|
continue-on-error: true
|
||||||
run: |
|
run: |
|
||||||
export ENOS_VAR_enos_user=$GITHUB_ACTOR && \
|
export ENOS_VAR_enos_user=$GITHUB_ACTOR && \
|
||||||
export ENOS_VAR_aws_ssh_private_key_path=~/.ssh/github_enos && \
|
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
|
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@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 }}"
|
||||||
@@ -9,7 +9,7 @@ jobs:
|
|||||||
trigger-gha-release:
|
trigger-gha-release:
|
||||||
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
runs-on: ${{ fromJSON(vars.RUNNER) }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
- name: Release description
|
- name: Release description
|
||||||
run: |
|
run: |
|
||||||
echo "Triggering release with a TAG ${GITHUB_REF#refs/tags/}"
|
echo "Triggering release with a TAG ${GITHUB_REF#refs/tags/}"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) HashiCorp, Inc.
|
# Copyright IBM Corp. 2021, 2026
|
||||||
# SPDX-License-Identifier: BUSL-1.1
|
# SPDX-License-Identifier: BUSL-1.1
|
||||||
|
|
||||||
url_license = "https://github.com/hashicorp/boundary-ui/blob/main/LICENSE"
|
url_license = "https://github.com/hashicorp/boundary-ui/blob/main/LICENSE"
|
||||||
|
|||||||
Binary file not shown.
@@ -3,21 +3,21 @@ License text copyright (c) 2020 MariaDB Corporation Ab, All Rights Reserved.
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
|
|
||||||
Licensor: HashiCorp, Inc.
|
Licensor: International Business Machines Corporation (IBM)
|
||||||
Licensed Work: The Licensed Work is (c) 2024 HashiCorp, Inc.
|
Licensed Work: The Licensed Work is (c) 2024 IBM Corp.
|
||||||
Additional Use Grant: You may make production use of the Licensed Work, provided
|
Additional Use Grant: You may make production use of the Licensed Work, provided
|
||||||
Your use does not include offering the Licensed Work to third
|
Your use does not include offering the Licensed Work to third
|
||||||
parties on a hosted or embedded basis in order to compete with
|
parties on a hosted or embedded basis in order to compete with
|
||||||
HashiCorp's paid version(s) of the Licensed Work. For purposes
|
IBM Corp's paid version(s) of the Licensed Work. For purposes
|
||||||
of this license:
|
of this license:
|
||||||
|
|
||||||
A "competitive offering" is a Product that is offered to third
|
A "competitive offering" is a Product that is offered to third
|
||||||
parties on a paid basis, including through paid support
|
parties on a paid basis, including through paid support
|
||||||
arrangements, that significantly overlaps with the capabilities
|
arrangements, that significantly overlaps with the capabilities
|
||||||
of HashiCorp's paid version(s) of the Licensed Work. If Your
|
of IBM Corp's paid version(s) of the Licensed Work. If Your
|
||||||
Product is not a competitive offering when You first make it
|
Product is not a competitive offering when You first make it
|
||||||
generally available, it will not become a competitive offering
|
generally available, it will not become a competitive offering
|
||||||
later due to HashiCorp releasing a new version of the Licensed
|
later due to IBM Corp releasing a new version of the Licensed
|
||||||
Work with additional capabilities. In addition, Products that
|
Work with additional capabilities. In addition, Products that
|
||||||
are not provided on a paid basis are not competitive.
|
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
|
Hosting or using the Licensed Work(s) for internal purposes
|
||||||
within an organization is not considered a competitive
|
within an organization is not considered a competitive
|
||||||
offering. HashiCorp considers your organization to include all
|
offering. IBM Corp considers your organization to include all
|
||||||
of your affiliates under common control.
|
of your affiliates under common control.
|
||||||
|
|
||||||
For binding interpretive guidance on using HashiCorp products
|
For binding interpretive guidance on using IBM Corp products
|
||||||
under the Business Source License, please visit our FAQ.
|
under the Business Source License, please visit our FAQ.
|
||||||
(https://www.hashicorp.com/license-faq)
|
(https://www.hashicorp.com/license-faq)
|
||||||
Change Date: Four years from the date the Licensed Work is published.
|
Change Date: Four years from the date the Licensed Work is published.
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
# unconventional js
|
|
||||||
/blueprints/*/files/
|
|
||||||
|
|
||||||
# compiled output
|
|
||||||
/declarations/
|
|
||||||
/dist/
|
|
||||||
|
|
||||||
# misc
|
|
||||||
/coverage/
|
|
||||||
!.*
|
|
||||||
.*/
|
|
||||||
|
|
||||||
# ember-try
|
|
||||||
/.node_modules.ember-try/
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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: {
|
|
||||||
'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',
|
|
||||||
],
|
|
||||||
parserOptions: {
|
|
||||||
sourceType: 'script',
|
|
||||||
},
|
|
||||||
env: {
|
|
||||||
browser: false,
|
|
||||||
node: true,
|
|
||||||
},
|
|
||||||
extends: ['plugin:n/recommended'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// test files
|
|
||||||
files: ['tests/**/*-test.{js,ts}'],
|
|
||||||
extends: ['plugin:qunit/recommended'],
|
|
||||||
rules: {
|
|
||||||
'qunit/require-expect': [2, 'except-simple'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
+38
-5
@@ -21,17 +21,50 @@ This addon contains the API data access layer for Boundary.
|
|||||||
## Add API to an App
|
## Add API to an App
|
||||||
|
|
||||||
Add this addon to an Ember application's `devDependencies` as:
|
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.
|
||||||
|
|
||||||
Since this addon also includes Mirage mocks, be sure to install
|
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`
|
||||||
`ember-cli-mirage` and add the following config to your UI project:
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
'ember-cli-mirage': {
|
mirage: {
|
||||||
directory: '../../addons/api/mirage'
|
enabled: true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
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
|
## Installation
|
||||||
|
|
||||||
See monorepo README for installation instructions.
|
See monorepo README for installation instructions.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* 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.
|
* This test helper can be used to help setup your sinon stubs in your tests.
|
||||||
* Must be called after setupMirage.
|
* Must be called after setupMirage and setupDesktopContextBridgeApiMock in tests.
|
||||||
*
|
*
|
||||||
* ```js
|
* ```js
|
||||||
* import setupStubs from 'api/test-support/handlers/cache-daemon-search';
|
* import setupStubs from 'api/test-support/handlers/cache-daemon-search';
|
||||||
@@ -19,14 +19,15 @@ import { underscore } from '@ember/string';
|
|||||||
* module('Acceptance | my test', function(hooks) {
|
* module('Acceptance | my test', function(hooks) {
|
||||||
* setupApplicationTest(hooks);
|
* setupApplicationTest(hooks);
|
||||||
* setupMirage(hooks);
|
* setupMirage(hooks);
|
||||||
|
* setupDesktopContextBridgeApiMock(hooks);
|
||||||
* setupStubs(hooks);
|
* setupStubs(hooks);
|
||||||
*
|
*
|
||||||
* // add your actual tests here
|
* // add your actual tests here
|
||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* This will setup a stub for the IPC service and include helper methods to
|
* This will setup a stub for window.desktop.daemon.searchCacheDaemon and include
|
||||||
* help setup what the cache daemon search command returns.
|
* helper methods to help setup what the cache daemon search command returns.
|
||||||
*
|
*
|
||||||
* @module Test Helpers
|
* @module Test Helpers
|
||||||
* @public
|
* @public
|
||||||
@@ -35,9 +36,6 @@ export default function setupStubs(hooks) {
|
|||||||
let stubTypes = [];
|
let stubTypes = [];
|
||||||
|
|
||||||
hooks.beforeEach(function () {
|
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
|
* 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
|
* search. However, the handler expects the search data to be raw JSON from
|
||||||
@@ -56,20 +54,18 @@ export default function setupStubs(hooks) {
|
|||||||
stubTypes = types;
|
stubTypes = types;
|
||||||
|
|
||||||
types.forEach((type, i) => {
|
types.forEach((type, i) => {
|
||||||
let models;
|
this.searchCacheDaemonStub.onCall(i).callsFake(() => {
|
||||||
let resourceName;
|
let models;
|
||||||
if (typeOf(type) === 'object') {
|
let resourceName;
|
||||||
models = type.func();
|
if (typeOf(type) === 'object') {
|
||||||
resourceName = type.resource;
|
models = type.func();
|
||||||
} else {
|
resourceName = type.resource;
|
||||||
models = this.server.schema[type].all().models;
|
} else {
|
||||||
resourceName = type;
|
models = this.server.schema[type].all().models;
|
||||||
}
|
resourceName = type;
|
||||||
|
}
|
||||||
|
|
||||||
this.ipcStub
|
return {
|
||||||
.withArgs('searchCacheDaemon')
|
|
||||||
.onCall(i)
|
|
||||||
.returns({
|
|
||||||
[underscore(resourceNames[singularize(resourceName)])]: models.map(
|
[underscore(resourceNames[singularize(resourceName)])]: models.map(
|
||||||
(model) => {
|
(model) => {
|
||||||
// Use internal serializer to serialize the model correctly
|
// Use internal serializer to serialize the model correctly
|
||||||
@@ -82,7 +78,8 @@ export default function setupStubs(hooks) {
|
|||||||
return JSON.parse(JSON.stringify(modelData));
|
return JSON.parse(JSON.stringify(modelData));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
});
|
};
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -90,22 +87,19 @@ export default function setupStubs(hooks) {
|
|||||||
hooks.afterEach(function () {
|
hooks.afterEach(function () {
|
||||||
// Verify the number of mocks we set up match with how
|
// Verify the number of mocks we set up match with how
|
||||||
// many times the cache daemon was called with
|
// many times the cache daemon was called with
|
||||||
sinon.assert.callCount(
|
sinon.assert.callCount(this.searchCacheDaemonStub, stubTypes.length);
|
||||||
this.ipcStub.withArgs('searchCacheDaemon'),
|
|
||||||
stubTypes.length,
|
|
||||||
);
|
|
||||||
|
|
||||||
stubTypes.forEach((type, i) => {
|
stubTypes.forEach((type, i) => {
|
||||||
// Assert that the stub was called with the resource we're trying to mock
|
// Assert that the stub was called with the resource we're trying to mock
|
||||||
// so we don't mistakenly mock the wrong resource
|
// so we don't mistakenly mock the wrong resource
|
||||||
const ipcCall = this.ipcStub.withArgs('searchCacheDaemon').getCall(i);
|
const call = this.searchCacheDaemonStub.getCall(i);
|
||||||
let resource = type;
|
let resource = type;
|
||||||
if (typeOf(type) === 'object') {
|
if (typeOf(type) === 'object') {
|
||||||
resource = type.resource;
|
resource = type.resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mappedResourceName = resourceNames[singularize(resource)];
|
const mappedResourceName = resourceNames[singularize(resource)];
|
||||||
sinon.assert.match(ipcCall.args[1], { resource: mappedResourceName });
|
sinon.assert.match(call.args[0], { resource: mappedResourceName });
|
||||||
});
|
});
|
||||||
|
|
||||||
sinon.restore();
|
sinon.restore();
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* 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,35 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) HashiCorp, Inc.
|
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This test helper can help set up and cleanup the database in your tests.
|
|
||||||
*
|
|
||||||
* ```js
|
|
||||||
* import { setupIndexedDb } from 'api/test-support/helpers/indexed-db';
|
|
||||||
*
|
|
||||||
* module('Acceptance | my test', function(hooks) {
|
|
||||||
* setupApplicationTest(hooks);
|
|
||||||
* setupIndexedDb(hooks);
|
|
||||||
*
|
|
||||||
* // add your actual tests here
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @param hooks
|
|
||||||
*/
|
|
||||||
export function setupIndexedDb(hooks) {
|
|
||||||
hooks.beforeEach(async function () {
|
|
||||||
const indexedDb = this.owner.lookup('service:indexed-db');
|
|
||||||
await indexedDb.setup(`test-indexed-db-${Date.now()}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
hooks.afterEach(async function () {
|
|
||||||
const indexedDb = this.owner.lookup('service:indexed-db');
|
|
||||||
|
|
||||||
await indexedDb.db.delete();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export default setupIndexedDb;
|
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* Copyright IBM Corp. 2021, 2026
|
||||||
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test helper can help set up and cleanup the database in your tests.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* import { setupSqlite } from 'api/test-support/helpers/sqlite';
|
||||||
|
*
|
||||||
|
* module('Acceptance | my test', function(hooks) {
|
||||||
|
* setupApplicationTest(hooks);
|
||||||
|
* setupSqlite(hooks);
|
||||||
|
*
|
||||||
|
* // add your actual tests here
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param hooks
|
||||||
|
*/
|
||||||
|
export function setupSqlite(hooks) {
|
||||||
|
hooks.beforeEach(async function () {
|
||||||
|
const sqliteDb = this.owner.lookup('service:sqlite');
|
||||||
|
await sqliteDb.setup(`test-sqlite-${uuidv4()}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
hooks.afterEach(async function () {
|
||||||
|
const sqliteDb = this.owner.lookup('service:sqlite');
|
||||||
|
|
||||||
|
await sqliteDb.deleteDatabase();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default setupSqlite;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ class InvalidRolePrincipalTypeError extends Error {
|
|||||||
export default class RoleAbility extends ModelAbility {
|
export default class RoleAbility extends ModelAbility {
|
||||||
// =services
|
// =services
|
||||||
|
|
||||||
@service can;
|
@service abilities;
|
||||||
|
|
||||||
// =permissions
|
// =permissions
|
||||||
|
|
||||||
@@ -59,10 +59,11 @@ export default class RoleAbility extends ModelAbility {
|
|||||||
const type = this.model.constructor.modelName;
|
const type = this.model.constructor.modelName;
|
||||||
const typeIsValid =
|
const typeIsValid =
|
||||||
type === 'user' || type === 'group' || type === 'managed-group';
|
type === 'user' || type === 'group' || type === 'managed-group';
|
||||||
if (!typeIsValid)
|
if (!typeIsValid) {
|
||||||
throw new InvalidRolePrincipalTypeError(
|
throw new InvalidRolePrincipalTypeError(
|
||||||
`Expected a role principal of type 'user', 'group', or 'managed-group'. Got '${type}'.`,
|
`Expected a role principal of type 'user', 'group', or 'managed-group'. Got '${type}'.`,
|
||||||
);
|
);
|
||||||
return this.can.can(`read ${type}`, this.model);
|
}
|
||||||
|
return this.abilities.can(`read ${type}`, this.model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -44,7 +44,8 @@ export default class TargetAbility extends ModelAbility {
|
|||||||
*/
|
*/
|
||||||
get canAddInjectedApplicationCredentialSources() {
|
get canAddInjectedApplicationCredentialSources() {
|
||||||
return (
|
return (
|
||||||
this.model.isSSH && this.hasAuthorizedAction('add-credential-sources')
|
(this.model.isSSH || this.model.isRDP) &&
|
||||||
|
this.hasAuthorizedAction('add-credential-sources')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ export default class HostCatalogAdapter extends ApplicationAdapter {
|
|||||||
try {
|
try {
|
||||||
const pluginName = snapshot.attr('plugin')?.name;
|
const pluginName = snapshot.attr('plugin')?.name;
|
||||||
if (pluginName) url = `${url}?plugin_name=${pluginName}`;
|
if (pluginName) url = `${url}?plugin_name=${pluginName}`;
|
||||||
} catch (e) {
|
} catch {
|
||||||
// Ignore any adapter errors here
|
// Ignore any adapter errors here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ export default class SessionRecordingAdapter extends ApplicationAdapter {
|
|||||||
let method;
|
let method;
|
||||||
try {
|
try {
|
||||||
method = snapshot?.adapterOptions?.method;
|
method = snapshot?.adapterOptions?.method;
|
||||||
} catch (e) {
|
} catch {
|
||||||
// Ignore any adapter errors here
|
// Ignore any adapter errors here
|
||||||
}
|
}
|
||||||
if (method === 'download') {
|
if (method === 'download') {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ export default class StorageBucketAdapter extends ApplicationAdapter {
|
|||||||
let pluginName;
|
let pluginName;
|
||||||
try {
|
try {
|
||||||
pluginName = snapshot?.attr('plugin')?.name;
|
pluginName = snapshot?.attr('plugin')?.name;
|
||||||
} catch (e) {
|
} catch {
|
||||||
// Ignore any adapter errors here
|
// Ignore any adapter errors here
|
||||||
}
|
}
|
||||||
if (requestType === 'createRecord' && pluginName) {
|
if (requestType === 'createRecord' && pluginName) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -81,9 +81,10 @@ export default class GeneratedCredentialLibraryModel extends BaseModel {
|
|||||||
})
|
})
|
||||||
credential_type;
|
credential_type;
|
||||||
|
|
||||||
@attr('object-as-array', {
|
@attr('object', {
|
||||||
for: 'vault-generic',
|
for: 'vault-generic',
|
||||||
description: 'It indicates the credential mapping overrides.',
|
description: 'It indicates the credential mapping overrides.',
|
||||||
|
emptyObjectIfMissing: true,
|
||||||
})
|
})
|
||||||
credential_mapping_overrides;
|
credential_mapping_overrides;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -51,17 +51,17 @@ export default class GeneratedCredentialModel extends BaseModel {
|
|||||||
})
|
})
|
||||||
version;
|
version;
|
||||||
|
|
||||||
// =attributes (username_password, ssh_private_key)
|
// =attributes (username_password, ssh_private_key, username_password_domain)
|
||||||
@attr('string', {
|
@attr('string', {
|
||||||
for: ['username_password', 'ssh_private_key'],
|
for: ['username_password', 'ssh_private_key', 'username_password_domain'],
|
||||||
isNestedAttribute: true,
|
isNestedAttribute: true,
|
||||||
description: 'The username for credential.',
|
description: 'The username for credential.',
|
||||||
})
|
})
|
||||||
username;
|
username;
|
||||||
|
|
||||||
// =attributes (username_password)
|
// =attributes (username_password, username_password_domain, password)
|
||||||
@attr('string', {
|
@attr('string', {
|
||||||
for: 'username_password',
|
for: ['username_password', 'username_password_domain', 'password'],
|
||||||
isNestedAttribute: true,
|
isNestedAttribute: true,
|
||||||
isSecret: true,
|
isSecret: true,
|
||||||
description: 'The password for credential.',
|
description: 'The password for credential.',
|
||||||
@@ -92,4 +92,12 @@ export default class GeneratedCredentialModel extends BaseModel {
|
|||||||
description: 'The secret associated with credential.',
|
description: 'The secret associated with credential.',
|
||||||
})
|
})
|
||||||
json_object;
|
json_object;
|
||||||
|
|
||||||
|
// =attributes (username_password_domain)
|
||||||
|
@attr('string', {
|
||||||
|
for: 'username_password_domain',
|
||||||
|
isNestedAttribute: true,
|
||||||
|
description: 'The domain for credential.',
|
||||||
|
})
|
||||||
|
domain;
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ export default class GeneratedHostCatalogModel extends BaseModel {
|
|||||||
@attr('string', {
|
@attr('string', {
|
||||||
for: {
|
for: {
|
||||||
type: 'plugin',
|
type: 'plugin',
|
||||||
name: ['aws', 'gcp'],
|
name: ['aws', 'azure', 'gcp'],
|
||||||
},
|
},
|
||||||
description:
|
description:
|
||||||
'An expression used to filter the workers that have network access to a service that is hosting the external object store.',
|
'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 (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -59,7 +59,6 @@ const fetchControllerData = async (context, next) => {
|
|||||||
*/
|
*/
|
||||||
export default class CacheDaemonHandler {
|
export default class CacheDaemonHandler {
|
||||||
@service session;
|
@service session;
|
||||||
@service ipc;
|
|
||||||
|
|
||||||
constructor(context) {
|
constructor(context) {
|
||||||
setOwner(this, getOwner(context));
|
setOwner(this, getOwner(context));
|
||||||
@@ -70,9 +69,8 @@ export default class CacheDaemonHandler {
|
|||||||
case 'query': {
|
case 'query': {
|
||||||
const { store, data } = context.request;
|
const { store, data } = context.request;
|
||||||
const { type, query, options: { pushToStore = true } = {} } = data;
|
const { type, query, options: { pushToStore = true } = {} } = data;
|
||||||
const isCacheDaemonRunning = await this.ipc.invoke(
|
const isCacheDaemonRunning =
|
||||||
'isCacheDaemonRunning',
|
await window.desktop.daemon.isCacheDaemonRunning();
|
||||||
);
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
let { recursive, scope_id, page, pageSize, ...remainingQuery } = query;
|
let { recursive, scope_id, page, pageSize, ...remainingQuery } = query;
|
||||||
@@ -101,6 +99,14 @@ export default class CacheDaemonHandler {
|
|||||||
const token = sessionData?.token;
|
const token = sessionData?.token;
|
||||||
const resourceName = resourceNames[type];
|
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 = {
|
||||||
...remainingQuery,
|
...remainingQuery,
|
||||||
query: searchQuery,
|
query: searchQuery,
|
||||||
@@ -111,23 +117,19 @@ export default class CacheDaemonHandler {
|
|||||||
|
|
||||||
let cacheDaemonResults = {};
|
let cacheDaemonResults = {};
|
||||||
try {
|
try {
|
||||||
cacheDaemonResults = await this.ipc.invoke(
|
cacheDaemonResults =
|
||||||
'searchCacheDaemon',
|
await window.desktop.daemon.searchCacheDaemon(remainingQuery);
|
||||||
remainingQuery,
|
|
||||||
);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// If we got a 403, most likely the cache daemon was restarted and our token is no longer valid
|
// 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
|
// 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) {
|
if (e.statusCode === 403 || e.statusCode === 401) {
|
||||||
try {
|
try {
|
||||||
await this.ipc.invoke('addTokenToDaemons', {
|
await window.desktop.daemon.addTokenToDaemons({
|
||||||
tokenId: auth_token_id,
|
tokenId: auth_token_id,
|
||||||
token,
|
token,
|
||||||
});
|
});
|
||||||
cacheDaemonResults = await this.ipc.invoke(
|
cacheDaemonResults =
|
||||||
'searchCacheDaemon',
|
await window.desktop.daemon.searchCacheDaemon(remainingQuery);
|
||||||
remainingQuery,
|
|
||||||
);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// If it fails again just fall back to fetching controller data
|
// If it fails again just fall back to fetching controller data
|
||||||
__electronLog?.error(
|
__electronLog?.error(
|
||||||
|
|||||||
@@ -1,242 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) HashiCorp, Inc.
|
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { modelIndexes } from 'api/services/indexed-db';
|
|
||||||
import { service } from '@ember/service';
|
|
||||||
import { getOwner, setOwner } from '@ember/application';
|
|
||||||
import { queryIndexedDb } from '../utils/indexed-db-query';
|
|
||||||
import { paginateResults } from '../utils/paginate-results';
|
|
||||||
import { sortResults } from '../utils/sort-results';
|
|
||||||
import { hashCode } from '../utils/hash-code';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler to sit in front of the API request layer
|
|
||||||
* so we can handle any caching with indexedDb first
|
|
||||||
*/
|
|
||||||
export default class IndexedDbHandler {
|
|
||||||
@service indexedDb;
|
|
||||||
|
|
||||||
batchLimit = 10_000;
|
|
||||||
|
|
||||||
constructor(context) {
|
|
||||||
setOwner(this, getOwner(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
async request(context, next) {
|
|
||||||
const { batchLimit } = this;
|
|
||||||
|
|
||||||
switch (context.request.op) {
|
|
||||||
case 'query': {
|
|
||||||
const { store, data } = context.request;
|
|
||||||
// TODO: Remove storeToken option as this is a temporary fix for auth-methods.
|
|
||||||
const {
|
|
||||||
type,
|
|
||||||
query,
|
|
||||||
options: {
|
|
||||||
pushToStore = true,
|
|
||||||
peekIndexedDB = false,
|
|
||||||
storeToken = true,
|
|
||||||
} = {},
|
|
||||||
} = data;
|
|
||||||
const supportedModels = Object.keys(modelIndexes);
|
|
||||||
const { db: indexedDb } = this.indexedDb ?? {};
|
|
||||||
|
|
||||||
// Go through normal flow if we don't yet support the model
|
|
||||||
// or if we don't have an indexedDb instance
|
|
||||||
if (!supportedModels.includes(type) || !indexedDb) {
|
|
||||||
return next(context.request);
|
|
||||||
}
|
|
||||||
|
|
||||||
let { page, pageSize, query: queryObj, ...remainingQuery } = query;
|
|
||||||
|
|
||||||
const adapter = store.adapterFor(type);
|
|
||||||
const schema = store.modelFor(type);
|
|
||||||
const serializer = store.serializerFor(type);
|
|
||||||
|
|
||||||
if (!peekIndexedDB) {
|
|
||||||
const tokenKey = `${type}-${hashCode(remainingQuery)}`;
|
|
||||||
let payload;
|
|
||||||
let listToken;
|
|
||||||
let writeToIndexedDbPromise;
|
|
||||||
|
|
||||||
if (storeToken) {
|
|
||||||
const tokenObj = await indexedDb.token.get(tokenKey);
|
|
||||||
listToken = tokenObj?.token;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
try {
|
|
||||||
payload = await adapter.query(store, schema, {
|
|
||||||
...remainingQuery,
|
|
||||||
list_token: listToken,
|
|
||||||
batchLimit: batchLimit,
|
|
||||||
});
|
|
||||||
|
|
||||||
// await the previous writeToIndexedDbPromise before writing to indexedDb again
|
|
||||||
if (writeToIndexedDbPromise) {
|
|
||||||
await writeToIndexedDbPromise;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
payload = await this.retryQueryFailure({
|
|
||||||
err,
|
|
||||||
indexedDb,
|
|
||||||
type,
|
|
||||||
adapter,
|
|
||||||
store,
|
|
||||||
schema,
|
|
||||||
remainingQuery,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
listToken = payload.list_token;
|
|
||||||
|
|
||||||
// Don't await immediately and let the next query run while we write to indexedDb
|
|
||||||
writeToIndexedDbPromise = this.writeToIndexedDb({
|
|
||||||
payload,
|
|
||||||
storeToken,
|
|
||||||
indexedDb,
|
|
||||||
tokenKey,
|
|
||||||
type,
|
|
||||||
serializer,
|
|
||||||
store,
|
|
||||||
schema,
|
|
||||||
});
|
|
||||||
} while (payload.response_type === 'delta');
|
|
||||||
|
|
||||||
await writeToIndexedDbPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Results returned in JSON API reponse, but in a format optimized for indexedDb
|
|
||||||
const indexedDbResults = await queryIndexedDb(
|
|
||||||
indexedDb,
|
|
||||||
type,
|
|
||||||
queryObj,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Normalize the results and clean up indexedDb format, ready for ember data consumption
|
|
||||||
const normalizedResults = indexedDbResults.map((item) => {
|
|
||||||
return this.indexedDb.normalizeData({
|
|
||||||
data: item,
|
|
||||||
cleanData: false,
|
|
||||||
schema,
|
|
||||||
serializer,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sort the results
|
|
||||||
const sortedResults = sortResults(normalizedResults, {
|
|
||||||
querySort: queryObj?.sort,
|
|
||||||
schema,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Paginate the results
|
|
||||||
const paginatedResults = paginateResults(sortedResults, page, pageSize);
|
|
||||||
|
|
||||||
// If we are not pushing to the store, use the raw data with id property
|
|
||||||
const records = pushToStore
|
|
||||||
? store.push({ data: paginatedResults })
|
|
||||||
: paginatedResults.map((record) => ({
|
|
||||||
...record.attributes,
|
|
||||||
id: record.id,
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Set a meta property on the array to store the total items of the results.
|
|
||||||
// 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: indexedDbResults.length };
|
|
||||||
return records;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return next(context.request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async retryQueryFailure({
|
|
||||||
err,
|
|
||||||
indexedDb,
|
|
||||||
type,
|
|
||||||
adapter,
|
|
||||||
store,
|
|
||||||
schema,
|
|
||||||
remainingQuery,
|
|
||||||
}) {
|
|
||||||
// If we get an invalid list token, we'll delete the token and
|
|
||||||
// clear the DB and try again without a token.
|
|
||||||
if (
|
|
||||||
err?.errors[0].status === 400 &&
|
|
||||||
err?.errors[0].code === 'invalid list token'
|
|
||||||
) {
|
|
||||||
await indexedDb[type].clear();
|
|
||||||
// Delete all tokens of the same resource type so we don't keep clearing the DB.
|
|
||||||
// Even if other tokens may still be valid, we might have cleared data that they
|
|
||||||
// depended on so we should clear all tokens of the same type when clearing the DB.
|
|
||||||
const tokenKeys = await indexedDb.token
|
|
||||||
.where(':id')
|
|
||||||
.startsWith(type)
|
|
||||||
.primaryKeys();
|
|
||||||
|
|
||||||
await indexedDb.token.bulkDelete(tokenKeys);
|
|
||||||
|
|
||||||
return await adapter.query(store, schema, {
|
|
||||||
...remainingQuery,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async writeToIndexedDb({
|
|
||||||
payload,
|
|
||||||
storeToken,
|
|
||||||
indexedDb,
|
|
||||||
tokenKey,
|
|
||||||
type,
|
|
||||||
serializer,
|
|
||||||
store,
|
|
||||||
schema,
|
|
||||||
}) {
|
|
||||||
// Store the token we just got back from the payload if it exists
|
|
||||||
if (payload.list_token && storeToken) {
|
|
||||||
await indexedDb.token.put({
|
|
||||||
id: tokenKey,
|
|
||||||
token: payload.list_token,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove any records from the DB if the API indicates they've been deleted
|
|
||||||
if (payload.removed_ids?.length > 0) {
|
|
||||||
await indexedDb[type].bulkDelete(payload.removed_ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// from the API call and we do not want deleted items from showing in list view.
|
|
||||||
if (!storeToken) {
|
|
||||||
await indexedDb[type].clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
const normalizedPayload = serializer.normalizeResponse(
|
|
||||||
store,
|
|
||||||
schema,
|
|
||||||
payload,
|
|
||||||
null,
|
|
||||||
'query',
|
|
||||||
);
|
|
||||||
|
|
||||||
const { data: payloadData } = normalizedPayload;
|
|
||||||
|
|
||||||
// Store the new data we just got back from the API refresh
|
|
||||||
const items = payloadData.map((datum) =>
|
|
||||||
this.indexedDb.normalizeData({
|
|
||||||
data: datum,
|
|
||||||
cleanData: true,
|
|
||||||
schema,
|
|
||||||
serializer,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
await indexedDb[type].bulkPut(items);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,274 @@
|
|||||||
|
/**
|
||||||
|
* Copyright IBM Corp. 2021, 2026
|
||||||
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { getOwner, setOwner } from '@ember/owner';
|
||||||
|
import { service } from '@ember/service';
|
||||||
|
import { modelMapping } from 'api/services/sqlite';
|
||||||
|
import { get } from '@ember/object';
|
||||||
|
import { typeOf } from '@ember/utils';
|
||||||
|
import { hashCode } from '../utils/hash-code';
|
||||||
|
import { generateSQLExpressions } from '../utils/sqlite-query';
|
||||||
|
|
||||||
|
const isISODateString = (str) =>
|
||||||
|
typeOf(str) === 'string' &&
|
||||||
|
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z?$/.test(str);
|
||||||
|
|
||||||
|
export default class SqliteHandler {
|
||||||
|
@service sqlite;
|
||||||
|
|
||||||
|
batchLimit = 5_000;
|
||||||
|
|
||||||
|
constructor(context) {
|
||||||
|
setOwner(this, getOwner(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
async request(context, next) {
|
||||||
|
switch (context.request.op) {
|
||||||
|
case 'query': {
|
||||||
|
const { store, data } = context.request;
|
||||||
|
const {
|
||||||
|
type,
|
||||||
|
query,
|
||||||
|
options: {
|
||||||
|
pushToStore = true,
|
||||||
|
peekDb = false,
|
||||||
|
storeToken = true,
|
||||||
|
} = {},
|
||||||
|
} = data;
|
||||||
|
const supportedModels = Object.keys(modelMapping);
|
||||||
|
|
||||||
|
// Go through normal flow if we don't yet support the model
|
||||||
|
// or if we don't have a sqlite db instance
|
||||||
|
if (!supportedModels.includes(type) || !this.sqlite.worker) {
|
||||||
|
return next(context.request);
|
||||||
|
}
|
||||||
|
|
||||||
|
const adapter = store.adapterFor(type);
|
||||||
|
const schema = store.modelFor(type);
|
||||||
|
const serializer = store.serializerFor(type);
|
||||||
|
|
||||||
|
let {
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
|
select,
|
||||||
|
query: queryObj,
|
||||||
|
...remainingQuery
|
||||||
|
} = query;
|
||||||
|
let payload,
|
||||||
|
listToken,
|
||||||
|
writeToDbPromise,
|
||||||
|
totalInsert = 0;
|
||||||
|
|
||||||
|
if (!peekDb) {
|
||||||
|
const tokenKey = `${type}-${hashCode(remainingQuery)}`;
|
||||||
|
if (storeToken) {
|
||||||
|
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
|
||||||
|
// from the API call and we do not want deleted items from showing in list view.
|
||||||
|
await this.sqlite.deleteResource(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
payload = await adapter.query(store, schema, {
|
||||||
|
...remainingQuery,
|
||||||
|
list_token: listToken,
|
||||||
|
batchLimit: this.batchLimit,
|
||||||
|
});
|
||||||
|
totalInsert += payload.items?.length ?? 0;
|
||||||
|
|
||||||
|
// await the previous writeToDbPromise before writing to db again
|
||||||
|
if (writeToDbPromise) {
|
||||||
|
await writeToDbPromise;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
payload = await this.retryQueryFailure({
|
||||||
|
err,
|
||||||
|
type,
|
||||||
|
adapter,
|
||||||
|
store,
|
||||||
|
schema,
|
||||||
|
remainingQuery,
|
||||||
|
});
|
||||||
|
totalInsert += payload.items?.length ?? 0;
|
||||||
|
}
|
||||||
|
listToken = payload.list_token;
|
||||||
|
|
||||||
|
writeToDbPromise = this.writeToDb(
|
||||||
|
payload,
|
||||||
|
storeToken,
|
||||||
|
tokenKey,
|
||||||
|
pushToStore,
|
||||||
|
serializer,
|
||||||
|
store,
|
||||||
|
schema,
|
||||||
|
type,
|
||||||
|
);
|
||||||
|
} while (payload.response_type === 'delta');
|
||||||
|
|
||||||
|
await writeToDbPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalInsert > 0) {
|
||||||
|
// If there were any inserts, let sqlite handle running analyze on the DB
|
||||||
|
await this.sqlite.analyzeDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
const { sql, parameters } = generateSQLExpressions(type, queryObj, {
|
||||||
|
page,
|
||||||
|
pageSize,
|
||||||
|
select: select ?? [{ field: 'data' }],
|
||||||
|
});
|
||||||
|
|
||||||
|
const rows = await this.sqlite.fetchResource({
|
||||||
|
sql,
|
||||||
|
parameters,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { sql: countSql, parameters: countParams } =
|
||||||
|
generateSQLExpressions(type, queryObj, {
|
||||||
|
select: [{ field: '*', isCount: true, alias: 'total' }],
|
||||||
|
});
|
||||||
|
const count = await this.sqlite.fetchResource({
|
||||||
|
sql: countSql,
|
||||||
|
parameters: countParams,
|
||||||
|
});
|
||||||
|
|
||||||
|
const results = rows.map((item) =>
|
||||||
|
JSON.parse(item.data, (key, value) =>
|
||||||
|
// Reviver function to convert any ISO strings back to date objects
|
||||||
|
// as we had to initially convert them to strings when stored in SQLite
|
||||||
|
isISODateString(value) ? new Date(value) : value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// If we are not pushing to the store, use the raw data with id property
|
||||||
|
const records = pushToStore
|
||||||
|
? store.push({ data: results })
|
||||||
|
: results.map((record) => ({
|
||||||
|
...record.attributes,
|
||||||
|
id: record.id,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Set a meta property on the array to store the total items of the results.
|
||||||
|
// 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 };
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return next(context.request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async retryQueryFailure({
|
||||||
|
err,
|
||||||
|
type,
|
||||||
|
adapter,
|
||||||
|
store,
|
||||||
|
schema,
|
||||||
|
remainingQuery,
|
||||||
|
}) {
|
||||||
|
// If we get an invalid list token, we'll delete the token and
|
||||||
|
// clear the DB and try again without a token.
|
||||||
|
if (
|
||||||
|
err?.errors?.[0].status === 400 &&
|
||||||
|
err?.errors?.[0].code === 'invalid list token'
|
||||||
|
) {
|
||||||
|
await this.sqlite.deleteResource(type);
|
||||||
|
// Delete all tokens of the same resource type so we don't keep clearing the DB.
|
||||||
|
// Even if other tokens may still be valid, we might have cleared data that they
|
||||||
|
// depended on so we should clear all tokens of the same type when clearing the DB.
|
||||||
|
const { sql, parameters } = generateSQLExpressions('token', {
|
||||||
|
filters: { id: [{ contains: type }] },
|
||||||
|
});
|
||||||
|
const tokenRows = await this.sqlite.fetchResource({
|
||||||
|
sql,
|
||||||
|
parameters,
|
||||||
|
});
|
||||||
|
const tokenIds = tokenRows.map((row) => row.id);
|
||||||
|
|
||||||
|
if (tokenIds.length > 0) {
|
||||||
|
await this.sqlite.deleteResource('token', tokenIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await adapter.query(store, schema, {
|
||||||
|
...remainingQuery,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async writeToDb(
|
||||||
|
payload,
|
||||||
|
storeToken,
|
||||||
|
tokenKey,
|
||||||
|
pushToStore,
|
||||||
|
serializer,
|
||||||
|
store,
|
||||||
|
schema,
|
||||||
|
type,
|
||||||
|
) {
|
||||||
|
if (payload.list_token && storeToken) {
|
||||||
|
await this.sqlite.insertResource('token', [
|
||||||
|
[tokenKey, payload.list_token],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalizedPayload = serializer.normalizeResponse(
|
||||||
|
store,
|
||||||
|
schema,
|
||||||
|
payload,
|
||||||
|
null,
|
||||||
|
'query',
|
||||||
|
);
|
||||||
|
|
||||||
|
const { data: payloadData } = normalizedPayload;
|
||||||
|
|
||||||
|
// Remove any records from the DB if the API indicates they've been deleted
|
||||||
|
// Additionally remove deleted records from ember data store for symmetry
|
||||||
|
if (payload.removed_ids?.length > 0) {
|
||||||
|
await this.sqlite.deleteResource(type, payload.removed_ids);
|
||||||
|
|
||||||
|
if (pushToStore) {
|
||||||
|
payload.removed_ids.forEach((id) => {
|
||||||
|
const record = store.peekRecord(type, id);
|
||||||
|
store.unloadRecord(record);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the new data we just got back from the API refresh
|
||||||
|
const items = payloadData.map((datum) => {
|
||||||
|
const params = Object.values(modelMapping[type]).map((key) => {
|
||||||
|
let value;
|
||||||
|
|
||||||
|
if (key === 'id') {
|
||||||
|
value = datum.id;
|
||||||
|
} else {
|
||||||
|
value = get(datum, `attributes.${key}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeOf(value) === 'date') {
|
||||||
|
return value.toISOString();
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
|
||||||
|
return [...params, JSON.stringify(datum)];
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.sqlite.insertResource(type, items);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,27 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import GeneratedCredentialLibraryModel from '../generated/models/credential-library';
|
import GeneratedCredentialLibraryModel from '../generated/models/credential-library';
|
||||||
|
import {
|
||||||
|
TYPE_CREDENTIAL_SSH_PRIVATE_KEY,
|
||||||
|
TYPE_CREDENTIAL_USERNAME_PASSWORD_DOMAIN,
|
||||||
|
TYPE_CREDENTIAL_USERNAME_PASSWORD,
|
||||||
|
TYPE_CREDENTIAL_PASSWORD,
|
||||||
|
} from 'api/models/credential';
|
||||||
/**
|
/**
|
||||||
* Enum options for credential library.
|
* Enum options for credential library.
|
||||||
*/
|
*/
|
||||||
export const options = {
|
export const options = {
|
||||||
http_method: ['GET', 'POST'],
|
http_method: ['GET', 'POST'],
|
||||||
key_type: ['ed25519', 'ecdsa', 'rsa'],
|
key_type: ['ed25519', 'ecdsa', 'rsa'],
|
||||||
credential_types: ['ssh_private_key', 'username_password'],
|
credential_types: [
|
||||||
|
TYPE_CREDENTIAL_SSH_PRIVATE_KEY,
|
||||||
|
TYPE_CREDENTIAL_USERNAME_PASSWORD,
|
||||||
|
TYPE_CREDENTIAL_USERNAME_PASSWORD_DOMAIN,
|
||||||
|
TYPE_CREDENTIAL_PASSWORD,
|
||||||
|
],
|
||||||
mapping_overrides: {
|
mapping_overrides: {
|
||||||
username_password: ['username_attribute', 'password_attribute'],
|
username_password: ['username_attribute', 'password_attribute'],
|
||||||
ssh_private_key: [
|
ssh_private_key: [
|
||||||
@@ -19,12 +29,19 @@ export const options = {
|
|||||||
'private_key_passphrase_attribute',
|
'private_key_passphrase_attribute',
|
||||||
'username_attribute',
|
'username_attribute',
|
||||||
],
|
],
|
||||||
|
username_password_domain: [
|
||||||
|
'username_attribute',
|
||||||
|
'password_attribute',
|
||||||
|
'domain_attribute',
|
||||||
|
],
|
||||||
|
password: ['password_attribute'],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC = 'vault-generic';
|
export const TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC = 'vault-generic';
|
||||||
export const TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE =
|
export const TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE =
|
||||||
'vault-ssh-certificate';
|
'vault-ssh-certificate';
|
||||||
|
export const TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP = 'vault-ldap';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Supported Credential Library types.
|
* Supported Credential Library types.
|
||||||
@@ -32,6 +49,7 @@ export const TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE =
|
|||||||
export const TYPES_CREDENTIAL_LIBRARY = Object.freeze([
|
export const TYPES_CREDENTIAL_LIBRARY = Object.freeze([
|
||||||
TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
|
TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
|
||||||
TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE,
|
TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE,
|
||||||
|
TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export default class CredentialLibraryModel extends GeneratedCredentialLibraryModel {
|
export default class CredentialLibraryModel extends GeneratedCredentialLibraryModel {
|
||||||
@@ -52,7 +70,8 @@ export default class CredentialLibraryModel extends GeneratedCredentialLibraryMo
|
|||||||
get isVault() {
|
get isVault() {
|
||||||
return (
|
return (
|
||||||
this.type === TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC ||
|
this.type === TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC ||
|
||||||
this.type === TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE
|
this.type === TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE ||
|
||||||
|
this.type === TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,4 +90,12 @@ export default class CredentialLibraryModel extends GeneratedCredentialLibraryMo
|
|||||||
get isVaultSSHCertificate() {
|
get isVaultSSHCertificate() {
|
||||||
return this.type === TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE;
|
return this.type === TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if credential is a vault ldap type.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get isVaultLDAP() {
|
||||||
|
return this.type === TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -12,11 +12,16 @@ import GeneratedCredentialModel from '../generated/models/credential';
|
|||||||
export const TYPE_CREDENTIAL_USERNAME_PASSWORD = 'username_password';
|
export const TYPE_CREDENTIAL_USERNAME_PASSWORD = 'username_password';
|
||||||
export const TYPE_CREDENTIAL_SSH_PRIVATE_KEY = 'ssh_private_key';
|
export const TYPE_CREDENTIAL_SSH_PRIVATE_KEY = 'ssh_private_key';
|
||||||
export const TYPE_CREDENTIAL_JSON = 'json';
|
export const TYPE_CREDENTIAL_JSON = 'json';
|
||||||
|
export const TYPE_CREDENTIAL_USERNAME_PASSWORD_DOMAIN =
|
||||||
|
'username_password_domain';
|
||||||
|
export const TYPE_CREDENTIAL_PASSWORD = 'password';
|
||||||
|
|
||||||
export const TYPES_CREDENTIAL = Object.freeze([
|
export const TYPES_CREDENTIAL = Object.freeze([
|
||||||
TYPE_CREDENTIAL_USERNAME_PASSWORD,
|
TYPE_CREDENTIAL_USERNAME_PASSWORD,
|
||||||
TYPE_CREDENTIAL_SSH_PRIVATE_KEY,
|
TYPE_CREDENTIAL_SSH_PRIVATE_KEY,
|
||||||
|
TYPE_CREDENTIAL_USERNAME_PASSWORD_DOMAIN,
|
||||||
TYPE_CREDENTIAL_JSON,
|
TYPE_CREDENTIAL_JSON,
|
||||||
|
TYPE_CREDENTIAL_PASSWORD,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export default class CredentialModel extends GeneratedCredentialModel {
|
export default class CredentialModel extends GeneratedCredentialModel {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) HashiCorp, Inc.
|
* Copyright IBM Corp. 2021, 2026
|
||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
Loaded 100 of 2563 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user