Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
798cfc6828 | ||
|
|
d93986c4e2 | ||
|
|
879c196887 | ||
|
|
98170ed01e | ||
|
|
47a218cf8f | ||
|
|
879a58dcb8 | ||
|
|
f100190ac1 | ||
|
|
0902e42cb0 | ||
|
|
6b0958e4d8 | ||
|
|
82ea70f44b | ||
|
|
0bb72040db | ||
|
|
9d9a38510b | ||
|
|
a54aecee07 | ||
|
|
7dab184bb9 | ||
|
|
f068ac0b0c | ||
|
|
d07c33ca41 | ||
|
|
f073de774d | ||
|
|
1040a05880 | ||
|
|
002f64d676 | ||
|
|
c09efbae10 | ||
|
|
060f995f94 | ||
|
|
f1c5c99664 | ||
|
|
af5fb8e814 | ||
|
|
cf5334556f | ||
|
|
5c6c9bb69f | ||
|
|
26a77edbc7 | ||
|
|
3fc865d226 | ||
|
|
47d7ceccf7 | ||
|
|
38df28be55 | ||
|
|
6d7c86a08c | ||
|
|
58a31b880b | ||
|
|
453ab7911d | ||
|
|
93c8d481fd | ||
|
|
956f6fd04d | ||
|
|
912be13744 | ||
|
|
fc1b91c8f9 | ||
|
|
8e40b01caf | ||
|
|
20181c978f | ||
|
|
db78f1ae4d | ||
|
|
592bb15022 | ||
|
|
f002e14673 | ||
|
|
a1b455e5eb | ||
|
|
786e6130cd | ||
|
|
4db8b8e1e7 | ||
|
|
4be8d10323 | ||
|
|
c79a1fca79 | ||
|
|
d2d332b7d1 | ||
|
|
022ac0fffe | ||
|
|
f3622fb92b | ||
|
|
f8b5dcd824 | ||
|
|
056008e13e | ||
|
|
ea03d6e488 | ||
|
|
06cc64e6af | ||
|
|
4d3c993b0f | ||
|
|
cb972cfc8a | ||
|
|
13f1c5cc23 | ||
|
|
f366f0a858 | ||
|
|
08d9801829 | ||
|
|
3f17435507 | ||
|
|
b63ddadf45 | ||
|
|
3721f63edf | ||
|
|
8f34d83c15 | ||
|
|
def6959ee7 | ||
|
|
e76cc2eeeb | ||
|
|
9a47a3ac5a | ||
|
|
2e1cba641c | ||
|
|
842a84296a | ||
|
|
b86ce41e68 | ||
|
|
5f9a66e421 | ||
|
|
24fdd926f1 | ||
|
|
db50bfc9df | ||
|
|
3f4beaada8 | ||
|
|
5a9cbdd913 | ||
|
|
314c1b36f4 | ||
|
|
f71fc3a0a4 | ||
|
|
5a74220f38 | ||
|
|
3f2fc63b5b | ||
|
|
c0793cd254 | ||
|
|
fb9a080d2e | ||
|
|
9e0467cbf0 | ||
|
|
c48fdb2017 | ||
|
|
60c5e25902 | ||
|
|
1488bdf95e | ||
|
|
9e6d647949 | ||
|
|
2e36d3c3e2 | ||
|
|
9046c01238 | ||
|
|
ba0c7d5683 | ||
|
|
16a054519f | ||
|
|
a1fbfdc1ad | ||
|
|
21122f1f29 | ||
|
|
a899ad0b74 | ||
|
|
c7483e5602 | ||
|
|
7fa2541ddb | ||
|
|
05553643a6 | ||
|
|
47cf7995d3 | ||
|
|
c06d18940d | ||
|
|
1122735b87 | ||
|
|
9fec047506 | ||
|
|
916b261cdf | ||
|
|
15da4ea69f | ||
|
|
f801f595f7 | ||
|
|
7af8e71a2d | ||
|
|
15d815c271 | ||
|
|
dfd484dbca | ||
|
|
50e4a2adbc | ||
|
|
7bc2ccb5ae | ||
|
|
3f11019ef0 | ||
|
|
1135f88cb7 | ||
|
|
221ab1f7bd | ||
|
|
4bf1a88764 | ||
|
|
b8b970ce4d | ||
|
|
25c6ed6100 | ||
|
|
550dee9ae0 | ||
|
|
776c46f129 | ||
|
|
6ae3067dd9 | ||
|
|
459029530b | ||
|
|
7dbd581a37 | ||
|
|
9bbd914a3a | ||
|
|
276713697a | ||
|
|
ba786d2172 | ||
|
|
ee4e19ace7 | ||
|
|
eefb9eba4f | ||
|
|
1cb3b708a2 | ||
|
|
8ad4e93ff7 | ||
|
|
9241b7dd0e | ||
|
|
0beec7b8fe | ||
|
|
9bcaa6dc68 | ||
|
|
3f178363d9 | ||
|
|
3810217ce7 | ||
|
|
b79eebf73a | ||
|
|
b3abb658ab | ||
|
|
245cfb395e | ||
|
|
adfa118ae5 | ||
|
|
cf0f4ab56a | ||
|
|
f40878034d | ||
|
|
01a986e08b | ||
|
|
e3406d9a95 | ||
|
|
d4adbe4317 | ||
|
|
01d4a329ab | ||
|
|
659067dd08 | ||
|
|
ade1601d8d | ||
|
|
4550cd0965 | ||
|
|
0bbc33d073 | ||
|
|
69a4eb53b9 | ||
|
|
d06111c803 | ||
|
|
b51c8203ee | ||
|
|
a94572214c | ||
|
|
751b5bef78 | ||
|
|
77f8235ebf | ||
|
|
9782f7e243 | ||
|
|
6328cc1fcf | ||
|
|
b986064447 | ||
|
|
6fbf243c31 | ||
|
|
66eca93f56 | ||
|
|
45d706dd40 | ||
|
|
99cf4c8d81 | ||
|
|
49923d968e | ||
|
|
b4a83a46d1 | ||
|
|
238ced63f7 | ||
|
|
602e4e62c3 | ||
|
|
f282dbb5b1 | ||
|
|
3f2f2ba756 | ||
|
|
02a89bd7ba | ||
|
|
a891f7a1a5 | ||
|
|
019b3e7390 | ||
|
|
bcf004b8a4 | ||
|
|
cb3a9e3bdc | ||
|
|
4127f6abd7 | ||
|
|
45a3cb8d34 | ||
|
|
e96171cab0 | ||
|
|
a7bf9a1071 | ||
|
|
3b3a00e1ee | ||
|
|
222f0c35b8 | ||
|
|
666491548d | ||
|
|
2558ee1353 |
No files matched your search
+14
-7
@@ -2,22 +2,29 @@
|
|||||||
# SPDX-License-Identifier: MPL-2.0
|
# SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
- addons/**/*
|
- changed-files:
|
||||||
|
- any-glob-to-any-file: "addons/**/*"
|
||||||
|
|
||||||
api-addon:
|
api-addon:
|
||||||
- addons/api/**/*
|
- changed-files:
|
||||||
|
- any-glob-to-any-file: "addons/api/**/*"
|
||||||
|
|
||||||
auth-addon:
|
auth-addon:
|
||||||
- addons/auth/**/*
|
- changed-files:
|
||||||
|
- any-glob-to-any-file: "addons/auth/**/*"
|
||||||
|
|
||||||
styles-addon:
|
styles-addon:
|
||||||
- addons/rose/**/*
|
- changed-files:
|
||||||
|
- any-glob-to-any-file: "addons/rose/**/*"
|
||||||
|
|
||||||
ui:
|
ui:
|
||||||
- ui/**/*
|
- changed-files:
|
||||||
|
- any-glob-to-any-file: "ui/**/*"
|
||||||
|
|
||||||
admin:
|
admin:
|
||||||
- ui/admin/**/*
|
- changed-files:
|
||||||
|
- any-glob-to-any-file: "ui/admin/**/*"
|
||||||
|
|
||||||
desktop:
|
desktop:
|
||||||
- ui/desktop/**/*
|
- changed-files:
|
||||||
|
- any-glob-to-any-file: "ui/desktop/**/*"
|
||||||
@@ -12,14 +12,14 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||||
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
|
- uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
|
||||||
id: node-modules-cache
|
id: node-modules-cache
|
||||||
with:
|
with:
|
||||||
path: "**/node_modules"
|
path: "**/node_modules"
|
||||||
key: node-modules-${{ hashFiles('**/yarn.lock') }}
|
key: node-modules-${{ hashFiles('**/yarn.lock') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
node-modules-
|
node-modules-
|
||||||
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
- run: yarn install
|
- run: yarn install
|
||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||||
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
|
- uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
|
||||||
id: node-modules-cache
|
id: node-modules-cache
|
||||||
with:
|
with:
|
||||||
path: "**/node_modules"
|
path: "**/node_modules"
|
||||||
@@ -37,17 +37,17 @@ jobs:
|
|||||||
restore-keys: |
|
restore-keys: |
|
||||||
node-modules-
|
node-modules-
|
||||||
- name: Build
|
- name: Build
|
||||||
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
- run: yarn run build:ui:admin:oss
|
- run: yarn run build:ui:admin:oss
|
||||||
- name: Upload artifact admin-ui
|
- name: Upload artifact admin-ui
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||||
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@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||||
with:
|
with:
|
||||||
name: admin-ui-oss
|
name: admin-ui-oss
|
||||||
path: ./ui/admin/dist/
|
path: ./ui/admin/dist/
|
||||||
@@ -57,7 +57,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||||
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
|
- uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
|
||||||
id: node-modules-cache
|
id: node-modules-cache
|
||||||
with:
|
with:
|
||||||
path: "**/node_modules"
|
path: "**/node_modules"
|
||||||
@@ -65,12 +65,12 @@ jobs:
|
|||||||
restore-keys: |
|
restore-keys: |
|
||||||
node-modules-
|
node-modules-
|
||||||
- name: Build
|
- name: Build
|
||||||
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
- run: yarn run build:ui:admin:enterprise
|
- run: yarn run build:ui:admin:enterprise
|
||||||
- name: Upload artifact enterprise admin UI
|
- name: Upload artifact enterprise admin UI
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||||
with:
|
with:
|
||||||
name: admin-ui-ent
|
name: admin-ui-ent
|
||||||
path: ./ui/admin/dist/
|
path: ./ui/admin/dist/
|
||||||
@@ -80,7 +80,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||||
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
|
- uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
|
||||||
id: node-modules-cache
|
id: node-modules-cache
|
||||||
with:
|
with:
|
||||||
path: "**/node_modules"
|
path: "**/node_modules"
|
||||||
@@ -88,12 +88,12 @@ jobs:
|
|||||||
restore-keys: |
|
restore-keys: |
|
||||||
node-modules-
|
node-modules-
|
||||||
- name: Build
|
- name: Build
|
||||||
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
- run: yarn run build:ui:admin:hcp
|
- run: yarn run build:ui:admin:hcp
|
||||||
- name: Upload artifact HCP admin UI
|
- name: Upload artifact HCP admin UI
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||||
with:
|
with:
|
||||||
name: admin-ui-hcp
|
name: admin-ui-hcp
|
||||||
path: ./ui/admin/dist/
|
path: ./ui/admin/dist/
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
name: "Trigger Build Artifacts for Testing"
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
branch:
|
||||||
|
description: Please use tag-like format n.n.n-someword (1.111.11-beta)
|
||||||
|
required: true
|
||||||
|
product_version:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: The version number belonging to the oss binary to be used
|
||||||
|
commit:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
description: The git SHA of the oss artifacts to be used
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
trigger-gha-build-artifacts-for-testing:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Release description
|
||||||
|
if: github.event_name == 'workflow_dispatch'
|
||||||
|
run: |
|
||||||
|
echo "Triggering Build Artifacts for Testing using BRANCH and TEST_TAG ${{ github.event.inputs.branch }}"
|
||||||
|
- name: Trigger Build Artifacts for Testing in boundary-ui-releases
|
||||||
|
run: |
|
||||||
|
export GITHUB_TOKEN="${{ secrets.ELEVATED_GITHUB_TOKEN }}"
|
||||||
|
gh workflow run build-artifacts-for-testing.yml \
|
||||||
|
--repo hashicorp/boundary-ui-releases \
|
||||||
|
--ref main \
|
||||||
|
-f TAG="${{ inputs.branch }}" \
|
||||||
|
-f PRODUCT_VERSION="${{ inputs.product_version }}" \
|
||||||
|
-f COMMIT="${{ inputs.commit }}" \
|
||||||
@@ -34,7 +34,7 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@bad341350a2f5616f9e048e51360cedc49181ce8 # codeql-bundle-v2.15.1
|
uses: github/codeql-action/init@592977e6ae857384aa79bb31e7a1d62d63449ec5 # codeql-bundle-v2.16.3
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
@@ -54,4 +54,4 @@ jobs:
|
|||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@bad341350a2f5616f9e048e51360cedc49181ce8 # codeql-bundle-v2.15.1
|
uses: github/codeql-action/analyze@592977e6ae857384aa79bb31e7a1d62d63449ec5 # codeql-bundle-v2.16.3
|
||||||
@@ -6,6 +6,6 @@ jobs:
|
|||||||
triage:
|
triage:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/labeler@ac9175f8a1f3625fd0d4fb234536d26811351594 # v4.3.0
|
- uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0
|
||||||
with:
|
with:
|
||||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
@@ -7,14 +7,14 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||||
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
|
- uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
|
||||||
id: node-modules-cache
|
id: node-modules-cache
|
||||||
with:
|
with:
|
||||||
path: '**/node_modules'
|
path: '**/node_modules'
|
||||||
key: node-modules-${{ hashFiles('**/yarn.lock') }}
|
key: node-modules-${{ hashFiles('**/yarn.lock') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
node-modules-
|
node-modules-
|
||||||
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
- run: yarn install
|
- run: yarn install
|
||||||
@@ -25,14 +25,14 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||||
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
|
- uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
|
||||||
id: node-modules-cache
|
id: node-modules-cache
|
||||||
with:
|
with:
|
||||||
path: '**/node_modules'
|
path: '**/node_modules'
|
||||||
key: node-modules-${{ hashFiles('**/yarn.lock') }}
|
key: node-modules-${{ hashFiles('**/yarn.lock') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
node-modules-
|
node-modules-
|
||||||
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
- run: yarn run compliance:licenses
|
- run: yarn run compliance:licenses
|
||||||
@@ -44,14 +44,14 @@ jobs:
|
|||||||
timeout-minutes: 5
|
timeout-minutes: 5
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||||
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
|
- uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
|
||||||
id: node-modules-cache
|
id: node-modules-cache
|
||||||
with:
|
with:
|
||||||
path: '**/node_modules'
|
path: '**/node_modules'
|
||||||
key: node-modules-${{ hashFiles('**/yarn.lock') }}
|
key: node-modules-${{ hashFiles('**/yarn.lock') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
node-modules-
|
node-modules-
|
||||||
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
- run: yarn lint
|
- run: yarn lint
|
||||||
@@ -63,12 +63,12 @@ jobs:
|
|||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||||
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
|
- uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
|
||||||
id: node-modules-cache
|
id: node-modules-cache
|
||||||
with:
|
with:
|
||||||
path: '**/node_modules'
|
path: '**/node_modules'
|
||||||
key: node-modules-${{ hashFiles('**/yarn.lock') }}
|
key: node-modules-${{ hashFiles('**/yarn.lock') }}
|
||||||
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
- run: yarn test
|
- run: yarn test
|
||||||
@@ -59,6 +59,9 @@ module.exports = {
|
|||||||
// Test files:
|
// Test files:
|
||||||
files: ['tests/**/*-test.{js,ts}'],
|
files: ['tests/**/*-test.{js,ts}'],
|
||||||
extends: ['plugin:qunit/recommended'],
|
extends: ['plugin:qunit/recommended'],
|
||||||
|
rules: {
|
||||||
|
'qunit/require-expect': [2, 'except-simple'],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import sinon from 'sinon';
|
||||||
|
import { typeOf } from '@ember/utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test helper can be used to help setup your sinon stubs in your tests.
|
||||||
|
* Must be called after setupMirage.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* import setupStubs from 'api/test-support/handlers/client-daemon-search';
|
||||||
|
*
|
||||||
|
* module('Acceptance | my test', function(hooks) {
|
||||||
|
* setupApplicationTest(hooks);
|
||||||
|
* setupMirage(hooks);
|
||||||
|
* setupStubs(hooks);
|
||||||
|
*
|
||||||
|
* // add your actual tests here
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* This will setup a stub for the IPC service and include helper methods to
|
||||||
|
* help setup what the client daemon search command returns.
|
||||||
|
*
|
||||||
|
* @module Test Helpers
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export default function setupStubs(hooks) {
|
||||||
|
let stubTypes = [];
|
||||||
|
|
||||||
|
hooks.beforeEach(function () {
|
||||||
|
const ipcService = this.owner.lookup('service:ipc');
|
||||||
|
this.ipcStub = sinon.stub(ipcService, 'invoke');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We aim to still use mirage data when stubbing out the client daemon
|
||||||
|
* search. However, the handler expects the search data to be raw JSON from
|
||||||
|
* the API which will get serialized. We add back the scope object for it to
|
||||||
|
* get correctly normalized and other fields such as "attributes" from the
|
||||||
|
* API will already be hoisted and will not be re-normalized from mirage data.
|
||||||
|
*
|
||||||
|
* This convenience method can take in multiple types,
|
||||||
|
* e.g. this.stubClientDaemonSearch('targets', 'sessions').
|
||||||
|
* This will have sinon stub out each call so the first call to search will
|
||||||
|
* provide all the models from the first parameter you specify,
|
||||||
|
* the second call will provide all the models from the second argument, etc.
|
||||||
|
* @param types
|
||||||
|
*/
|
||||||
|
this.stubClientDaemonSearch = (...types) => {
|
||||||
|
stubTypes = types;
|
||||||
|
|
||||||
|
types.forEach((type, i) => {
|
||||||
|
let models;
|
||||||
|
let resourceName;
|
||||||
|
if (typeOf(type) === 'object') {
|
||||||
|
models = type.func();
|
||||||
|
resourceName = type.resource;
|
||||||
|
} else {
|
||||||
|
models = this.server.schema[type].all().models;
|
||||||
|
resourceName = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ipcStub
|
||||||
|
.withArgs('searchClientDaemon')
|
||||||
|
.onCall(i)
|
||||||
|
.returns({
|
||||||
|
[resourceName]: models.map((model) => {
|
||||||
|
// Use internal serializer to serialize the model correctly
|
||||||
|
// according to our mirage serializers
|
||||||
|
const modelData =
|
||||||
|
this.server.serializerOrRegistry.serialize(model);
|
||||||
|
|
||||||
|
// Serialize the data properly to standard JSON as that is what
|
||||||
|
// we're expecting from the client daemon response
|
||||||
|
return JSON.parse(JSON.stringify(modelData));
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
hooks.afterEach(function () {
|
||||||
|
// Verify the number of mocks we set up match with how
|
||||||
|
// many times the client daemon was called with
|
||||||
|
sinon.assert.callCount(
|
||||||
|
this.ipcStub.withArgs('searchClientDaemon'),
|
||||||
|
stubTypes.length,
|
||||||
|
);
|
||||||
|
|
||||||
|
stubTypes.forEach((type, i) => {
|
||||||
|
// Assert that the stub was called with the resource we're trying to mock
|
||||||
|
// so we don't mistakenly mock the wrong resource
|
||||||
|
const ipcCall = this.ipcStub.withArgs('searchClientDaemon').getCall(i);
|
||||||
|
let resource = type;
|
||||||
|
if (typeOf(type) === 'object') {
|
||||||
|
resource = type.resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
sinon.assert.match(ipcCall.args[1], { resource });
|
||||||
|
});
|
||||||
|
|
||||||
|
sinon.restore();
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ export default class ChannelRecordingAbility extends ModelAbility {
|
|||||||
const sessionRecording = this.model.connection_recording.session_recording;
|
const sessionRecording = this.model.connection_recording.session_recording;
|
||||||
const sessionRecordingAbility = this.abilities.abilityFor(
|
const sessionRecordingAbility = this.abilities.abilityFor(
|
||||||
'session-recording',
|
'session-recording',
|
||||||
sessionRecording
|
sessionRecording,
|
||||||
);
|
);
|
||||||
|
|
||||||
return this.model.isAsciicast && sessionRecordingAbility.canDownload;
|
return this.model.isAsciicast && sessionRecordingAbility.canDownload;
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ModelAbility from './model';
|
||||||
|
import { service } from '@ember/service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides abilities for storage policies.
|
||||||
|
*/
|
||||||
|
export default class PolicyAbility extends ModelAbility {
|
||||||
|
// =services
|
||||||
|
@service features;
|
||||||
|
// =permissions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This ensures that storage policies may be read only if the
|
||||||
|
* session-recording feature flag is enabled.
|
||||||
|
*/
|
||||||
|
get canRead() {
|
||||||
|
return this.features.isEnabled('ssh-session-recording')
|
||||||
|
? super.canRead
|
||||||
|
: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This ensures that storage policies may be updated only if the
|
||||||
|
* session-recording feature flag is enabled.
|
||||||
|
*/
|
||||||
|
get canUpdate() {
|
||||||
|
return this.features.isEnabled('ssh-session-recording')
|
||||||
|
? super.canUpdate
|
||||||
|
: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This ensures that storage policies may be deleted only if the
|
||||||
|
* session-recording feature flag is enabled.
|
||||||
|
*/
|
||||||
|
get canDelete() {
|
||||||
|
return this.features.isEnabled('ssh-session-recording')
|
||||||
|
? super.canDelete
|
||||||
|
: false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -54,7 +54,7 @@ export default class RoleAbility extends ModelAbility {
|
|||||||
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.can.can(`read ${type}`, this.model);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ModelAbility from './model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides abilities for scopes.
|
||||||
|
*/
|
||||||
|
export default class ScopeAbility extends ModelAbility {
|
||||||
|
// =permissions
|
||||||
|
/**
|
||||||
|
* Permission that checks whether a policy can be attached to a scope
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get canAttachStoragePolicy() {
|
||||||
|
return this.hasAuthorizedAction('attach-storage-policy');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permission that checks whether a policy can be detached to a scope
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get canDetachStoragePolicy() {
|
||||||
|
return this.hasAuthorizedAction('detach-storage-policy');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,7 +21,22 @@ export default class SessionRecordingAbility extends ModelAbility {
|
|||||||
return !this.model.isUnknown && super.canRead;
|
return !this.model.isUnknown && super.canRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only "known" session recording types may be deleted.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get canDelete() {
|
||||||
|
return !this.model.isUnknown && super.canDelete && this.model.isAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
get canDownload() {
|
get canDownload() {
|
||||||
return this.hasAuthorizedAction('download');
|
return this.hasAuthorizedAction('download');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Permission that checks whether a policy can be reapplied to a session recording
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get canReapplyStoragePolicy() {
|
||||||
|
return this.hasAuthorizedAction('reapply-storage-policy');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ function prenormalizeArrayResponse(response) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class ApplicationAdapter extends RESTAdapter.extend(
|
export default class ApplicationAdapter extends RESTAdapter.extend(
|
||||||
AdapterBuildURLMixin
|
AdapterBuildURLMixin,
|
||||||
) {
|
) {
|
||||||
// =attributes
|
// =attributes
|
||||||
|
|
||||||
@@ -108,22 +108,37 @@ export default class ApplicationAdapter extends RESTAdapter.extend(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Intercepts "empty" responses and adds an empty `items` array.
|
* Intercepts "empty" responses and adds an empty `items` array.
|
||||||
* @override
|
* This query method now supports pagination by checking the responseType and
|
||||||
* @method findAll
|
* passing in the list token if the responseType indicates more data
|
||||||
* @return {Promise} promise
|
|
||||||
*/
|
|
||||||
findAll() {
|
|
||||||
return super.findAll(...arguments).then(prenormalizeArrayResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Intercepts "empty" responses and adds an empty `items` array.
|
|
||||||
* @override
|
* @override
|
||||||
* @method query
|
* @method query
|
||||||
* @return {Promise} promise
|
* @return {Promise} promise
|
||||||
*/
|
*/
|
||||||
query() {
|
async query(store, schema, query) {
|
||||||
return super.query(...arguments).then(prenormalizeArrayResponse);
|
let result;
|
||||||
|
let data = [];
|
||||||
|
|
||||||
|
// If the query has a page_size, we skip the pagination logic
|
||||||
|
// and return the initial result. This is being used to determine
|
||||||
|
// if the controller supports pagination
|
||||||
|
if (query.page_size) {
|
||||||
|
result = await super.query(store, schema, query);
|
||||||
|
return prenormalizeArrayResponse(result);
|
||||||
|
}
|
||||||
|
// Run this loop as long as the response_type is delta,
|
||||||
|
// which indicates that there are more items in the list
|
||||||
|
do {
|
||||||
|
result = await super.query(store, schema, query);
|
||||||
|
//add the result items to a data array
|
||||||
|
if (result && result.items) {
|
||||||
|
data.push(...result.items);
|
||||||
|
//pass in the list token for subsequent calls to fetch the remaining list items
|
||||||
|
query.list_token = result.list_token;
|
||||||
|
}
|
||||||
|
} while (result && result.response_type === 'delta');
|
||||||
|
|
||||||
|
result.items = data;
|
||||||
|
return prenormalizeArrayResponse(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export default class SessionRecordingAdapter extends ApplicationAdapter {
|
|||||||
throw this.handleResponse(
|
throw this.handleResponse(
|
||||||
response.status,
|
response.status,
|
||||||
response.headers,
|
response.headers,
|
||||||
await response.text()
|
await response.text(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import BaseModel from '../../models/base';
|
||||||
|
import { attr } from '@ember-data/model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias contains all fields related to an Alias resource
|
||||||
|
*/
|
||||||
|
export default class GeneratedAliasModel extends BaseModel {
|
||||||
|
// =attributes
|
||||||
|
|
||||||
|
@attr('string', {
|
||||||
|
description: 'The type of the resource, to help differentiate schemas',
|
||||||
|
})
|
||||||
|
type;
|
||||||
|
|
||||||
|
@attr('string', {
|
||||||
|
description: 'Optional name for identification purposes.',
|
||||||
|
})
|
||||||
|
name;
|
||||||
|
|
||||||
|
@attr('string', {
|
||||||
|
description: 'Optional user-set description for identification purposes.',
|
||||||
|
})
|
||||||
|
description;
|
||||||
|
|
||||||
|
@attr('date', {
|
||||||
|
description: 'The time this resource was created\nOutput only.',
|
||||||
|
readOnly: true,
|
||||||
|
})
|
||||||
|
created_time;
|
||||||
|
|
||||||
|
@attr('date', {
|
||||||
|
description: 'The time this resource was last updated\nOutput only.',
|
||||||
|
readOnly: true,
|
||||||
|
})
|
||||||
|
updated_time;
|
||||||
|
|
||||||
|
@attr('number', {
|
||||||
|
description: 'Current version number of this resource.',
|
||||||
|
})
|
||||||
|
version;
|
||||||
|
|
||||||
|
@attr('string', {
|
||||||
|
description: 'This is the id of the resource that this Alias points to.',
|
||||||
|
})
|
||||||
|
destination_id;
|
||||||
|
|
||||||
|
@attr('object', {
|
||||||
|
isNestedAttribute: true,
|
||||||
|
description:
|
||||||
|
'This contains a host_id which is the id of the host that the session will be authorized for.',
|
||||||
|
})
|
||||||
|
authorize_session_arguments;
|
||||||
|
}
|
||||||
@@ -158,6 +158,13 @@ export default class GeneratedAuthMethodModel extends BaseModel {
|
|||||||
})
|
})
|
||||||
account_claim_maps;
|
account_claim_maps;
|
||||||
|
|
||||||
|
@attr('string-array', {
|
||||||
|
for: 'oidc',
|
||||||
|
emptyArrayIfMissing: true,
|
||||||
|
isNestedAttribute: true,
|
||||||
|
})
|
||||||
|
prompts;
|
||||||
|
|
||||||
// =attributes(ldap)
|
// =attributes(ldap)
|
||||||
|
|
||||||
@attr('boolean', {
|
@attr('boolean', {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export default class GeneratedChannelRecordingModel extends BaseModel {
|
|||||||
'The total number of errors that occurred during the use of this Channel.',
|
'The total number of errors that occurred during the use of this Channel.',
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
})
|
})
|
||||||
errors;
|
errors_number;
|
||||||
|
|
||||||
@attr('date', {
|
@attr('date', {
|
||||||
description: 'The time the Channel started.',
|
description: 'The time the Channel started.',
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export default class GeneratedConnectionRecordingModel extends BaseModel {
|
|||||||
'The total number of errors that occurred during the use of this Connection.',
|
'The total number of errors that occurred during the use of this Connection.',
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
})
|
})
|
||||||
errors;
|
errors_number;
|
||||||
|
|
||||||
@attr('date', {
|
@attr('date', {
|
||||||
description: 'The time the Connection started.',
|
description: 'The time the Connection started.',
|
||||||
|
|||||||
@@ -75,6 +75,18 @@ export default class GeneratedCredentialLibraryModel extends BaseModel {
|
|||||||
})
|
})
|
||||||
path;
|
path;
|
||||||
|
|
||||||
|
@attr('string', {
|
||||||
|
for: 'vault-generic',
|
||||||
|
description: 'It indicates the type of credential the library returns.',
|
||||||
|
})
|
||||||
|
credential_type;
|
||||||
|
|
||||||
|
@attr('object', {
|
||||||
|
for: 'vault-generic',
|
||||||
|
description: 'It indicates the credential mapping overrides.',
|
||||||
|
})
|
||||||
|
credential_mapping_overrides;
|
||||||
|
|
||||||
@attr('string', {
|
@attr('string', {
|
||||||
for: 'vault-ssh-certificate',
|
for: 'vault-ssh-certificate',
|
||||||
isNestedAttribute: true,
|
isNestedAttribute: true,
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import BaseModel from '../../models/base';
|
||||||
|
import { attr } from '@ember-data/model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Storage Policy is a resource that manages the lifecycle of Session Recordings,
|
||||||
|
* particularly to meet compliance frameworks.
|
||||||
|
*/
|
||||||
|
export default class GeneratedPolicyModel extends BaseModel {
|
||||||
|
// =attributes
|
||||||
|
|
||||||
|
@attr('string', {
|
||||||
|
description: 'The type of the resource, to help differentiate schemas',
|
||||||
|
})
|
||||||
|
type;
|
||||||
|
|
||||||
|
@attr('string', {
|
||||||
|
description: 'Optional name for identification purposes.',
|
||||||
|
})
|
||||||
|
name;
|
||||||
|
|
||||||
|
@attr('string', {
|
||||||
|
description: 'Optional user-set description for identification purposes.',
|
||||||
|
})
|
||||||
|
description;
|
||||||
|
|
||||||
|
@attr('date', {
|
||||||
|
description: 'The time this resource was created\nOutput only.',
|
||||||
|
readOnly: true,
|
||||||
|
})
|
||||||
|
created_time;
|
||||||
|
|
||||||
|
@attr('date', {
|
||||||
|
description: 'The time this resource was last updated\nOutput only.',
|
||||||
|
readOnly: true,
|
||||||
|
})
|
||||||
|
updated_time;
|
||||||
|
|
||||||
|
@attr('number', {
|
||||||
|
description: 'Current version number of this resource.',
|
||||||
|
})
|
||||||
|
version;
|
||||||
|
|
||||||
|
@attr('object', {
|
||||||
|
isNestedAttribute: true,
|
||||||
|
description:
|
||||||
|
'Days is the number of days for which a session recording will be retained.',
|
||||||
|
})
|
||||||
|
retain_for;
|
||||||
|
|
||||||
|
@attr('object', {
|
||||||
|
isNestedAttribute: true,
|
||||||
|
description:
|
||||||
|
'Days is the number of days for which a session recording will be automatically deleted.',
|
||||||
|
})
|
||||||
|
delete_after;
|
||||||
|
}
|
||||||
@@ -49,4 +49,9 @@ export default class GeneratedScopeModel extends BaseModel {
|
|||||||
description: 'Current version number of this resource.',
|
description: 'Current version number of this resource.',
|
||||||
})
|
})
|
||||||
version;
|
version;
|
||||||
|
|
||||||
|
@attr('string', {
|
||||||
|
description: 'The ID of the associated storage policy',
|
||||||
|
})
|
||||||
|
storage_policy_id;
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,7 @@ export default class GeneratedSessionRecordingModel extends BaseModel {
|
|||||||
'The total number of errors that occurred during the use of the Session.',
|
'The total number of errors that occurred during the use of the Session.',
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
})
|
})
|
||||||
errors;
|
errors_number;
|
||||||
|
|
||||||
@attr('date', {
|
@attr('date', {
|
||||||
description: 'The time the Session started.',
|
description: 'The time the Session started.',
|
||||||
@@ -109,4 +109,17 @@ export default class GeneratedSessionRecordingModel extends BaseModel {
|
|||||||
readOnly: true,
|
readOnly: true,
|
||||||
})
|
})
|
||||||
error_details;
|
error_details;
|
||||||
|
|
||||||
|
@attr('date', {
|
||||||
|
description: 'The time until a session recording is required to be stored.',
|
||||||
|
readOnly: true,
|
||||||
|
})
|
||||||
|
retain_until;
|
||||||
|
|
||||||
|
@attr('date', {
|
||||||
|
description:
|
||||||
|
'The time a session recording is scheduled to be automatically deleted.',
|
||||||
|
readOnly: true,
|
||||||
|
})
|
||||||
|
delete_after;
|
||||||
}
|
}
|
||||||
@@ -32,6 +32,13 @@ export default class GeneratedSessionModel extends BaseModel {
|
|||||||
})
|
})
|
||||||
updated_time;
|
updated_time;
|
||||||
|
|
||||||
|
@attr('date', {
|
||||||
|
description:
|
||||||
|
'After this time the connection will be expired, e.g. forcefully terminated.\nOutput only.',
|
||||||
|
readOnly: true,
|
||||||
|
})
|
||||||
|
expiration_time;
|
||||||
|
|
||||||
@attr('number', {
|
@attr('number', {
|
||||||
description: 'Current version number of this resource.',
|
description: 'Current version number of this resource.',
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,181 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { inject as service } from '@ember/service';
|
||||||
|
import { getOwner, setOwner } from '@ember/application';
|
||||||
|
import { pluralize } from 'ember-inflector';
|
||||||
|
import { generateMQLExpression } from '../utils/mql-query';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not all types are yet supported by the client daemon so we'll
|
||||||
|
* just whitelist the ones we need to start with. Keys are the resource
|
||||||
|
* types and the values are the fields that are searchable by the client.
|
||||||
|
* @type {{session: string[], target: string[]}}
|
||||||
|
*/
|
||||||
|
const supportedTypes = {
|
||||||
|
target: ['id', 'name', 'description', 'address', 'scope_id'],
|
||||||
|
session: ['id', 'type', 'status', 'endpoint', 'scope_id', 'target_id'],
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes an array and the current page and pagesize to calculate the correct
|
||||||
|
* number of results to return to the caller.
|
||||||
|
*
|
||||||
|
* @param array
|
||||||
|
* @param page
|
||||||
|
* @param pageSize
|
||||||
|
* @returns {[*]}
|
||||||
|
*/
|
||||||
|
const paginateResults = (array, page, pageSize) => {
|
||||||
|
const length = array?.length;
|
||||||
|
if (!array || length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (!page || !pageSize) {
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
const offset = (page - 1) * pageSize;
|
||||||
|
const start = Math.min(length - 1, offset);
|
||||||
|
const end = Math.min(length, offset + pageSize);
|
||||||
|
|
||||||
|
return array.slice(start, end);
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchControllerData = async (context, next) => {
|
||||||
|
const { data } = context.request;
|
||||||
|
const { query: originalQuery } = data;
|
||||||
|
// remove client daemon specific query params
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
const { query, page, pageSize, ...remainingQuery } = originalQuery;
|
||||||
|
|
||||||
|
// If we get an error or client daemon is unavailable, fall back to calling the API
|
||||||
|
context.request.data.query = remainingQuery;
|
||||||
|
const results = await next(context.request);
|
||||||
|
const models = results.content.toArray();
|
||||||
|
|
||||||
|
const paginatedResult = paginateResults(models, page, pageSize);
|
||||||
|
paginatedResult.meta = { totalItems: models.length };
|
||||||
|
return paginatedResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler to sit in front of the API request layer
|
||||||
|
* so we can request from the daemon first
|
||||||
|
*/
|
||||||
|
export default class ClientDaemonHandler {
|
||||||
|
@service session;
|
||||||
|
@service ipc;
|
||||||
|
|
||||||
|
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 } = {} } = data;
|
||||||
|
const isClientDaemonRunning = await this.ipc.invoke(
|
||||||
|
'isClientDaemonRunning',
|
||||||
|
);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
let { recursive, scope_id, page, pageSize, ...remainingQuery } = query;
|
||||||
|
let searchQuery = '';
|
||||||
|
|
||||||
|
if (
|
||||||
|
!Object.keys(supportedTypes).includes(type) ||
|
||||||
|
!isClientDaemonRunning
|
||||||
|
) {
|
||||||
|
return fetchControllerData(context, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remainingQuery.query) {
|
||||||
|
const { search, filters } = remainingQuery.query;
|
||||||
|
|
||||||
|
searchQuery = generateMQLExpression({
|
||||||
|
search: {
|
||||||
|
text: search,
|
||||||
|
fields: supportedTypes[type],
|
||||||
|
},
|
||||||
|
filters,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const sessionData = this.session.data?.authenticated;
|
||||||
|
const auth_token_id = sessionData?.id;
|
||||||
|
const token = sessionData?.token;
|
||||||
|
remainingQuery = {
|
||||||
|
...remainingQuery,
|
||||||
|
query: searchQuery,
|
||||||
|
auth_token_id,
|
||||||
|
token,
|
||||||
|
resource: pluralize(type),
|
||||||
|
};
|
||||||
|
|
||||||
|
let clientDaemonResults = {};
|
||||||
|
try {
|
||||||
|
clientDaemonResults = await this.ipc.invoke(
|
||||||
|
'searchClientDaemon',
|
||||||
|
remainingQuery,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
// If we got a 403, most likely the client daemon was restarted and our token is no longer valid
|
||||||
|
// I'm not sure if we can get a 401 since we always send a token but we'll handle it in the same way
|
||||||
|
if (e.statusCode === 403 || e.statusCode === 401) {
|
||||||
|
try {
|
||||||
|
await this.ipc.invoke('addTokenToClientDaemon', {
|
||||||
|
tokenId: auth_token_id,
|
||||||
|
token,
|
||||||
|
});
|
||||||
|
clientDaemonResults = await this.ipc.invoke(
|
||||||
|
'searchClientDaemon',
|
||||||
|
remainingQuery,
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
// If it fails again just fall back to fetching controller data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetchControllerData(context, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Currently returns with a singular top level field with resource name
|
||||||
|
// e.g. { targets: [...] } or { sessions: [..] }
|
||||||
|
// So this just unwraps to the array, or undefined
|
||||||
|
const [results] = Object.values(clientDaemonResults);
|
||||||
|
const payload = { items: paginateResults(results, page, pageSize) };
|
||||||
|
|
||||||
|
const schema = store.modelFor(type);
|
||||||
|
const serializer = store.serializerFor(type);
|
||||||
|
const normalizedPayload = serializer.normalizeResponse(
|
||||||
|
store,
|
||||||
|
schema,
|
||||||
|
payload,
|
||||||
|
null,
|
||||||
|
'query',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Return the raw data if we don't push to the store.
|
||||||
|
let records = normalizedPayload.data.map((record) => ({
|
||||||
|
...record.attributes,
|
||||||
|
id: record.id,
|
||||||
|
}));
|
||||||
|
if (pushToStore) {
|
||||||
|
records = store.push(normalizedPayload);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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: results?.length ?? 0 };
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return next(context.request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -87,7 +87,7 @@ export default class AccountModel extends GeneratedAccountModel {
|
|||||||
changePassword(
|
changePassword(
|
||||||
currentPassword,
|
currentPassword,
|
||||||
newPassword,
|
newPassword,
|
||||||
options = { adapterOptions: {} }
|
options = { adapterOptions: {} },
|
||||||
) {
|
) {
|
||||||
const defaultAdapterOptions = {
|
const defaultAdapterOptions = {
|
||||||
method: 'change-password',
|
method: 'change-password',
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import GeneratedAliasModel from '../generated/models/alias';
|
||||||
|
|
||||||
|
export const TYPE_ALIAS_TARGET = 'target';
|
||||||
|
export const TYPES_ALIAS = Object.freeze([TYPE_ALIAS_TARGET]);
|
||||||
|
export default class AliasModel extends GeneratedAliasModel {}
|
||||||
@@ -37,6 +37,7 @@ export const options = {
|
|||||||
account_claim_maps: {
|
account_claim_maps: {
|
||||||
to: ['sub', 'name', 'email'],
|
to: ['sub', 'name', 'email'],
|
||||||
},
|
},
|
||||||
|
prompts: ['consent', 'select_account', 'login'],
|
||||||
},
|
},
|
||||||
ldap: {
|
ldap: {
|
||||||
account_attribute_maps: {
|
account_attribute_maps: {
|
||||||
|
|||||||
@@ -11,6 +11,18 @@ import GeneratedCredentialLibraryModel from '../generated/models/credential-libr
|
|||||||
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'],
|
||||||
|
mapping_overrides: {
|
||||||
|
username_password: {
|
||||||
|
username_attribute: 'Username',
|
||||||
|
password_attribute: 'Password',
|
||||||
|
},
|
||||||
|
ssh_private_key: {
|
||||||
|
private_key_attribute: 'Private Key',
|
||||||
|
private_key_passphrase_attribute: 'Private Key Passphrase',
|
||||||
|
username_attribute: 'Username',
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC = 'vault-generic';
|
export const TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC = 'vault-generic';
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import GeneratedPolicyModel from '../generated/models/policy';
|
||||||
|
|
||||||
|
export const TYPE_POLICY = 'storage';
|
||||||
|
export default class PolicyModel extends GeneratedPolicyModel {}
|
||||||
@@ -138,7 +138,7 @@ export default class RoleModel extends GeneratedRoleModel {
|
|||||||
const authMethods = this.resourceFilterStore.queryBy(
|
const authMethods = this.resourceFilterStore.queryBy(
|
||||||
'auth-method',
|
'auth-method',
|
||||||
{ type: [TYPE_AUTH_METHOD_OIDC, TYPE_AUTH_METHOD_LDAP] },
|
{ type: [TYPE_AUTH_METHOD_OIDC, TYPE_AUTH_METHOD_LDAP] },
|
||||||
{ scope_id: 'global', recursive: true }
|
{ scope_id: 'global', recursive: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
// For each auth method, query all managed groups with IDs
|
// For each auth method, query all managed groups with IDs
|
||||||
@@ -149,9 +149,9 @@ export default class RoleModel extends GeneratedRoleModel {
|
|||||||
methods.map(({ id: auth_method_id }) =>
|
methods.map(({ id: auth_method_id }) =>
|
||||||
this.resourceFilterStore
|
this.resourceFilterStore
|
||||||
.queryBy('managed-group', { id: ids }, { auth_method_id })
|
.queryBy('managed-group', { id: ids }, { auth_method_id })
|
||||||
.then((models) => models.map((model) => model))
|
.then((models) => models.map((model) => model)),
|
||||||
)
|
),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
// The result is an array of arrays of model instances (grouped by
|
// The result is an array of arrays of model instances (grouped by
|
||||||
// auth methods), so these must be flattened.
|
// auth methods), so these must be flattened.
|
||||||
|
|||||||
@@ -46,4 +46,48 @@ export default class ScopeModel extends GeneratedScopeModel {
|
|||||||
set isProject(value) {
|
set isProject(value) {
|
||||||
if (value) this.type = scopeTypes.project;
|
if (value) this.type = scopeTypes.project;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attach policy via the `attach-staorage-policy` method.
|
||||||
|
* @param {[string]} policyId
|
||||||
|
* @param {object} options
|
||||||
|
* @param {object} options.adapterOptions
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
|
attachStoragePolicy(policyId, options = { adapterOptions: {} }) {
|
||||||
|
const defaultAdapterOptions = {
|
||||||
|
method: 'attach-storage-policy',
|
||||||
|
policyId,
|
||||||
|
};
|
||||||
|
// There is no "deep merge" in ES.
|
||||||
|
return this.save({
|
||||||
|
...options,
|
||||||
|
adapterOptions: {
|
||||||
|
...defaultAdapterOptions,
|
||||||
|
...options.adapterOptions,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detaches policy via the `detach-storage-policy` method.
|
||||||
|
* @param {[string]} policyId
|
||||||
|
* @param {object} options
|
||||||
|
* @param {object} options.adapterOptions
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
|
detachStoragePolicy(policyId, options = { adapterOptions: {} }) {
|
||||||
|
const defaultAdapterOptions = {
|
||||||
|
method: 'detach-storage-policy',
|
||||||
|
policyId,
|
||||||
|
};
|
||||||
|
// There is no "deep merge" in ES.
|
||||||
|
return this.save({
|
||||||
|
...options,
|
||||||
|
adapterOptions: {
|
||||||
|
...defaultAdapterOptions,
|
||||||
|
...options.adapterOptions,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -69,4 +69,23 @@ export default class SessionRecordingModel extends GeneratedSessionRecordingMode
|
|||||||
this.create_time_values?.user?.name || this.create_time_values?.user?.id
|
this.create_time_values?.user?.name || this.create_time_values?.user?.id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reapply policy dates via the `reapply-staorage-policy` method.
|
||||||
|
* @param {object} options
|
||||||
|
* @param {object} options.adapterOptions
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
|
reapplyStoragePolicy(options = { adapterOptions: {} }) {
|
||||||
|
const defaultAdapterOptions = {
|
||||||
|
method: 'reapply-storage-policy',
|
||||||
|
};
|
||||||
|
return this.save({
|
||||||
|
...options,
|
||||||
|
adapterOptions: {
|
||||||
|
...defaultAdapterOptions,
|
||||||
|
...options.adapterOptions,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,7 @@ class SessionCredential {
|
|||||||
if (this.#payloadSecret?.decoded) {
|
if (this.#payloadSecret?.decoded) {
|
||||||
const secretJSON = this.#payloadSecret.decoded;
|
const secretJSON = this.#payloadSecret.decoded;
|
||||||
return Object.keys(secretJSON).map(
|
return Object.keys(secretJSON).map(
|
||||||
(key) => new SessionCredential.SecretItem(key, secretJSON[key])
|
(key) => new SessionCredential.SecretItem(key, secretJSON[key]),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// decode from base64
|
// decode from base64
|
||||||
|
|||||||
@@ -108,6 +108,14 @@ export default class TargetModel extends GeneratedTargetModel {
|
|||||||
.filter((s) => s && s.target_id === this.id);
|
.filter((s) => s && s.target_id === this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Available sessions associated with this target (but only already loaded sessions).
|
||||||
|
* @type {SessionModel[]}
|
||||||
|
*/
|
||||||
|
get availableSessions() {
|
||||||
|
return this.sessions.filter((session) => session.isAvailable);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The project associated with this target (if already loaded).
|
* The project associated with this target (if already loaded).
|
||||||
* @type {ScopeModel}
|
* @type {ScopeModel}
|
||||||
@@ -122,7 +130,7 @@ export default class TargetModel extends GeneratedTargetModel {
|
|||||||
*/
|
*/
|
||||||
get isActive() {
|
get isActive() {
|
||||||
const pendingOrActiveSessions = this.sessions.filter(
|
const pendingOrActiveSessions = this.sessions.filter(
|
||||||
(s) => s.isActive || s.isPending
|
(s) => s.isActive || s.isPending,
|
||||||
);
|
);
|
||||||
return Boolean(pendingOrActiveSessions.length);
|
return Boolean(pendingOrActiveSessions.length);
|
||||||
}
|
}
|
||||||
@@ -195,7 +203,7 @@ export default class TargetModel extends GeneratedTargetModel {
|
|||||||
*/
|
*/
|
||||||
addBrokeredCredentialSources(
|
addBrokeredCredentialSources(
|
||||||
brokeredCredentialSourceIDs,
|
brokeredCredentialSourceIDs,
|
||||||
options = { adapterOptions: {} }
|
options = { adapterOptions: {} },
|
||||||
) {
|
) {
|
||||||
const defaultAdapterOptions = {
|
const defaultAdapterOptions = {
|
||||||
method: 'add-credential-sources',
|
method: 'add-credential-sources',
|
||||||
@@ -221,7 +229,7 @@ export default class TargetModel extends GeneratedTargetModel {
|
|||||||
*/
|
*/
|
||||||
addInjectedApplicationCredentialSources(
|
addInjectedApplicationCredentialSources(
|
||||||
injectedApplicationCredentialSourceIDs,
|
injectedApplicationCredentialSourceIDs,
|
||||||
options = { adapterOptions: {} }
|
options = { adapterOptions: {} },
|
||||||
) {
|
) {
|
||||||
const defaultAdapterOptions = {
|
const defaultAdapterOptions = {
|
||||||
method: 'add-credential-sources',
|
method: 'add-credential-sources',
|
||||||
@@ -247,7 +255,7 @@ export default class TargetModel extends GeneratedTargetModel {
|
|||||||
*/
|
*/
|
||||||
removeBrokeredCredentialSources(
|
removeBrokeredCredentialSources(
|
||||||
brokeredCredentialSourceIDs,
|
brokeredCredentialSourceIDs,
|
||||||
options = { adapterOptions: {} }
|
options = { adapterOptions: {} },
|
||||||
) {
|
) {
|
||||||
const defaultAdapterOptions = {
|
const defaultAdapterOptions = {
|
||||||
method: 'remove-credential-sources',
|
method: 'remove-credential-sources',
|
||||||
@@ -272,7 +280,7 @@ export default class TargetModel extends GeneratedTargetModel {
|
|||||||
removeBrokeredCredentialSource(brokeredCredentialSourceID, options) {
|
removeBrokeredCredentialSource(brokeredCredentialSourceID, options) {
|
||||||
return this.removeBrokeredCredentialSources(
|
return this.removeBrokeredCredentialSources(
|
||||||
[brokeredCredentialSourceID],
|
[brokeredCredentialSourceID],
|
||||||
options
|
options,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,7 +294,7 @@ export default class TargetModel extends GeneratedTargetModel {
|
|||||||
*/
|
*/
|
||||||
removeInjectedApplicationCredentialSources(
|
removeInjectedApplicationCredentialSources(
|
||||||
injectedApplicationCredentialSourceIDs,
|
injectedApplicationCredentialSourceIDs,
|
||||||
options = { adapterOptions: {} }
|
options = { adapterOptions: {} },
|
||||||
) {
|
) {
|
||||||
const defaultAdapterOptions = {
|
const defaultAdapterOptions = {
|
||||||
method: 'remove-credential-sources',
|
method: 'remove-credential-sources',
|
||||||
@@ -310,11 +318,11 @@ export default class TargetModel extends GeneratedTargetModel {
|
|||||||
*/
|
*/
|
||||||
removeInjectedApplicationCredentialSource(
|
removeInjectedApplicationCredentialSource(
|
||||||
injectedApplicationCredentialSourceID,
|
injectedApplicationCredentialSourceID,
|
||||||
options
|
options,
|
||||||
) {
|
) {
|
||||||
return this.removeInjectedApplicationCredentialSources(
|
return this.removeInjectedApplicationCredentialSources(
|
||||||
[injectedApplicationCredentialSourceID],
|
[injectedApplicationCredentialSourceID],
|
||||||
options
|
options,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export default class WorkerModel extends GeneratedWorkerModel {
|
|||||||
|
|
||||||
return Object.values(this.config_tags).reduce(
|
return Object.values(this.config_tags).reduce(
|
||||||
(previousCount, currentTags) => previousCount + currentTags.length,
|
(previousCount, currentTags) => previousCount + currentTags.length,
|
||||||
0
|
0,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ export default class WorkerModel extends GeneratedWorkerModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Object.entries(this.config_tags).flatMap(([key, value]) =>
|
return Object.entries(this.config_tags).flatMap(([key, value]) =>
|
||||||
value.map((tag) => ({ key, value: tag }))
|
value.map((tag) => ({ key, value: tag })),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ export default class AccountSerializer extends ApplicationSerializer {
|
|||||||
serialized = this.serializeForChangePassword(
|
serialized = this.serializeForChangePassword(
|
||||||
snapshot,
|
snapshot,
|
||||||
currentPassword,
|
currentPassword,
|
||||||
newPassword
|
newPassword,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return serialized;
|
return serialized;
|
||||||
|
|||||||
@@ -145,18 +145,18 @@ export default class ApplicationSerializer extends RESTSerializer {
|
|||||||
const transformedPayload = {};
|
const transformedPayload = {};
|
||||||
// Find the Ember-data-expected root key name.
|
// Find the Ember-data-expected root key name.
|
||||||
const payloadKey = this.payloadKeyFromModelName(
|
const payloadKey = this.payloadKeyFromModelName(
|
||||||
primaryModelClass.modelName
|
primaryModelClass.modelName,
|
||||||
);
|
);
|
||||||
// Copy the data rooted under `items` in the existing payload into the new
|
// Copy the data rooted under `items` in the existing payload into the new
|
||||||
// payload under the expected root key name.
|
// payload under the expected root key name.
|
||||||
transformedPayload[payloadKey] = structuredClone(payload.items);
|
transformedPayload[payloadKey] = structuredClone(payload?.items);
|
||||||
// Return the result of normalizing the transformed payload.
|
// Return the result of normalizing the transformed payload.
|
||||||
return super.normalizeArrayResponse(
|
return super.normalizeArrayResponse(
|
||||||
store,
|
store,
|
||||||
primaryModelClass,
|
primaryModelClass,
|
||||||
transformedPayload,
|
transformedPayload,
|
||||||
id,
|
id,
|
||||||
requestType
|
requestType,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +183,7 @@ export default class ApplicationSerializer extends RESTSerializer {
|
|||||||
const transformedPayload = {};
|
const transformedPayload = {};
|
||||||
// Find the Ember-data-expected root key name.
|
// Find the Ember-data-expected root key name.
|
||||||
const payloadKey = this.payloadKeyFromModelName(
|
const payloadKey = this.payloadKeyFromModelName(
|
||||||
primaryModelClass.modelName
|
primaryModelClass.modelName,
|
||||||
);
|
);
|
||||||
// Copy the unrooted payload under the expected root key name.
|
// Copy the unrooted payload under the expected root key name.
|
||||||
transformedPayload[payloadKey] = payload;
|
transformedPayload[payloadKey] = payload;
|
||||||
@@ -193,7 +193,7 @@ export default class ApplicationSerializer extends RESTSerializer {
|
|||||||
primaryModelClass,
|
primaryModelClass,
|
||||||
transformedPayload,
|
transformedPayload,
|
||||||
id,
|
id,
|
||||||
requestType
|
requestType,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,7 +318,7 @@ export default class ApplicationSerializer extends RESTSerializer {
|
|||||||
primaryModelClass,
|
primaryModelClass,
|
||||||
payload,
|
payload,
|
||||||
id,
|
id,
|
||||||
requestType
|
requestType,
|
||||||
) {
|
) {
|
||||||
const newPayload = structuredClone(payload);
|
const newPayload = structuredClone(payload);
|
||||||
|
|
||||||
@@ -338,7 +338,7 @@ export default class ApplicationSerializer extends RESTSerializer {
|
|||||||
primaryModelClass,
|
primaryModelClass,
|
||||||
newPayload,
|
newPayload,
|
||||||
id,
|
id,
|
||||||
requestType
|
requestType,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,7 @@ export default class AuthMethodSerializer extends ApplicationSerializer {
|
|||||||
normalizeArrayResponse() {
|
normalizeArrayResponse() {
|
||||||
const normalized = super.normalizeArrayResponse(...arguments);
|
const normalized = super.normalizeArrayResponse(...arguments);
|
||||||
normalized.data = normalized.data.sort((a) =>
|
normalized.data = normalized.data.sort((a) =>
|
||||||
a.attributes.is_primary ? -1 : 1
|
a.attributes.is_primary ? -1 : 1,
|
||||||
);
|
);
|
||||||
return normalized;
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ApplicationSerializer from './application';
|
||||||
|
import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest';
|
||||||
|
|
||||||
|
export default class ChannelSerializer extends ApplicationSerializer.extend(
|
||||||
|
EmbeddedRecordsMixin,
|
||||||
|
) {
|
||||||
|
normalize(typeClass, hash, ...rest) {
|
||||||
|
const normalizedHash = structuredClone(hash);
|
||||||
|
const err = normalizedHash.errors;
|
||||||
|
delete normalizedHash.errors;
|
||||||
|
const normalized = super.normalize(typeClass, normalizedHash, ...rest);
|
||||||
|
// we should not override the ember models errors field,
|
||||||
|
// so we rename the errors field from the api
|
||||||
|
normalized.data.attributes.errors_number = err;
|
||||||
|
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,9 +7,21 @@ import ApplicationSerializer from './application';
|
|||||||
import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest';
|
import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest';
|
||||||
|
|
||||||
export default class ConnectionSerializer extends ApplicationSerializer.extend(
|
export default class ConnectionSerializer extends ApplicationSerializer.extend(
|
||||||
EmbeddedRecordsMixin
|
EmbeddedRecordsMixin,
|
||||||
) {
|
) {
|
||||||
attrs = {
|
attrs = {
|
||||||
channel_recordings: { embedded: 'always' },
|
channel_recordings: { embedded: 'always' },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
normalize(typeClass, hash, ...rest) {
|
||||||
|
const normalizedHash = structuredClone(hash);
|
||||||
|
const err = normalizedHash.errors;
|
||||||
|
delete normalizedHash.errors;
|
||||||
|
const normalized = super.normalize(typeClass, normalizedHash, ...rest);
|
||||||
|
// we should not override the ember models errors field,
|
||||||
|
// so we rename the errors field from the api
|
||||||
|
normalized.data.attributes.errors_number = err;
|
||||||
|
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@ import ApplicationSerializer from './application';
|
|||||||
import {
|
import {
|
||||||
TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
|
TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
|
||||||
TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE,
|
TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE,
|
||||||
|
options,
|
||||||
} from '../models/credential-library';
|
} from '../models/credential-library';
|
||||||
|
|
||||||
export default class CredentialLibrarySerializer extends ApplicationSerializer {
|
export default class CredentialLibrarySerializer extends ApplicationSerializer {
|
||||||
@@ -31,9 +32,34 @@ export default class CredentialLibrarySerializer extends ApplicationSerializer {
|
|||||||
return super.serialize(...arguments);
|
return super.serialize(...arguments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
serializeAttribute(snapshot, json) {
|
||||||
|
const value = super.serializeAttribute(...arguments);
|
||||||
|
const { credential_type, type, credential_mapping_overrides, isNew } =
|
||||||
|
snapshot.record;
|
||||||
|
if (
|
||||||
|
type === TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC &&
|
||||||
|
credential_mapping_overrides &&
|
||||||
|
credential_type &&
|
||||||
|
!isNew
|
||||||
|
) {
|
||||||
|
// API expects to send null to fields if it is undefined or deleted
|
||||||
|
json.credential_mapping_overrides = Object.keys(
|
||||||
|
options.mapping_overrides[credential_type],
|
||||||
|
).reduce((obj, key) => {
|
||||||
|
if (credential_mapping_overrides[key]) {
|
||||||
|
obj[key] = credential_mapping_overrides[key];
|
||||||
|
} else {
|
||||||
|
obj[key] = null;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
serializeVaultGeneric() {
|
serializeVaultGeneric() {
|
||||||
const serialized = super.serialize(...arguments);
|
const serialized = super.serialize(...arguments);
|
||||||
|
|
||||||
if (serialized.attributes) {
|
if (serialized.attributes) {
|
||||||
// Set `http_request_body` only if `http_method` is POST
|
// Set `http_request_body` only if `http_method` is POST
|
||||||
// otherwise set to null to have the field removed
|
// otherwise set to null to have the field removed
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export default class CredentialSerializer extends ApplicationSerializer {
|
|||||||
|
|
||||||
if (serialized?.attributes?.json_object) {
|
if (serialized?.attributes?.json_object) {
|
||||||
serialized.attributes.object = JSON.parse(
|
serialized.attributes.object = JSON.parse(
|
||||||
serialized.attributes.json_object
|
serialized.attributes.json_object,
|
||||||
);
|
);
|
||||||
delete serialized.attributes.json_object;
|
delete serialized.attributes.json_object;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ApplicationSerializer from './application';
|
||||||
|
|
||||||
|
export default class ScopeSerializer extends ApplicationSerializer {
|
||||||
|
// =methods
|
||||||
|
|
||||||
|
serialize(snapshot) {
|
||||||
|
let serialized = super.serialize(...arguments);
|
||||||
|
const policyId = snapshot?.adapterOptions?.policyId;
|
||||||
|
|
||||||
|
if (policyId) {
|
||||||
|
serialized = this.serializeWithStoragePolicy(snapshot, policyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return serialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a payload containing only version and storage policy id,
|
||||||
|
* rather than existing instances on the model.
|
||||||
|
* @param {Snapshot} snapshot
|
||||||
|
* @param {[string]} hostSetIDs
|
||||||
|
* @return {object}
|
||||||
|
*/
|
||||||
|
serializeWithStoragePolicy(snapshot, policyId) {
|
||||||
|
return {
|
||||||
|
version: snapshot.attr('version'),
|
||||||
|
storage_policy_id: policyId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,9 +6,31 @@
|
|||||||
import ApplicationSerializer from './application';
|
import ApplicationSerializer from './application';
|
||||||
import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest';
|
import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest';
|
||||||
export default class RecordingSerializer extends ApplicationSerializer.extend(
|
export default class RecordingSerializer extends ApplicationSerializer.extend(
|
||||||
EmbeddedRecordsMixin
|
EmbeddedRecordsMixin,
|
||||||
) {
|
) {
|
||||||
attrs = {
|
attrs = {
|
||||||
connection_recordings: { embedded: 'always' },
|
connection_recordings: { embedded: 'always' },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
serialize(snapshot) {
|
||||||
|
let serialized = super.serialize(...arguments);
|
||||||
|
// The post request for reapply-storage-policy doesn't expect a payload,
|
||||||
|
// so we return nothing
|
||||||
|
if (snapshot?.adapterOptions?.method === 'reapply-storage-policy') {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return serialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
normalize(typeClass, hash, ...rest) {
|
||||||
|
const normalizedHash = structuredClone(hash);
|
||||||
|
const err = normalizedHash.errors;
|
||||||
|
delete normalizedHash.errors;
|
||||||
|
const normalized = super.normalize(typeClass, normalizedHash, ...rest);
|
||||||
|
// we should not override the ember models errors field,
|
||||||
|
// so we rename the errors field from the api
|
||||||
|
normalized.data.attributes.errors_number = err;
|
||||||
|
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -36,12 +36,12 @@ export default class TargetSerializer extends ApplicationSerializer {
|
|||||||
if (brokeredCredentialSourceIDs)
|
if (brokeredCredentialSourceIDs)
|
||||||
serialized = this.serializeWithBrokeredCredentialSources(
|
serialized = this.serializeWithBrokeredCredentialSources(
|
||||||
snapshot,
|
snapshot,
|
||||||
brokeredCredentialSourceIDs
|
brokeredCredentialSourceIDs,
|
||||||
);
|
);
|
||||||
if (injectedApplicationCredentialSourceIDs)
|
if (injectedApplicationCredentialSourceIDs)
|
||||||
serialized = this.serializeWithInjectedApplicationCredentialSources(
|
serialized = this.serializeWithInjectedApplicationCredentialSources(
|
||||||
snapshot,
|
snapshot,
|
||||||
injectedApplicationCredentialSourceIDs
|
injectedApplicationCredentialSourceIDs,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Delete session recording related fields from non-SSH targets
|
// Delete session recording related fields from non-SSH targets
|
||||||
@@ -75,7 +75,7 @@ export default class TargetSerializer extends ApplicationSerializer {
|
|||||||
*/
|
*/
|
||||||
serializeWithBrokeredCredentialSources(
|
serializeWithBrokeredCredentialSources(
|
||||||
snapshot,
|
snapshot,
|
||||||
brokered_credential_source_ids
|
brokered_credential_source_ids,
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
version: snapshot.attr('version'),
|
version: snapshot.attr('version'),
|
||||||
@@ -92,7 +92,7 @@ export default class TargetSerializer extends ApplicationSerializer {
|
|||||||
*/
|
*/
|
||||||
serializeWithInjectedApplicationCredentialSources(
|
serializeWithInjectedApplicationCredentialSources(
|
||||||
snapshot,
|
snapshot,
|
||||||
injected_application_credential_source_ids
|
injected_application_credential_source_ids,
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
version: snapshot.attr('version'),
|
version: snapshot.attr('version'),
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default class WorkerSerializer extends ApplicationSerializer {
|
|||||||
if (workerGeneratedAuthToken)
|
if (workerGeneratedAuthToken)
|
||||||
serialized = this.serializeWithGeneratedToken(
|
serialized = this.serializeWithGeneratedToken(
|
||||||
snapshot,
|
snapshot,
|
||||||
workerGeneratedAuthToken
|
workerGeneratedAuthToken,
|
||||||
);
|
);
|
||||||
return serialized;
|
return serialized;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ export class ResourceFilter {
|
|||||||
return this.in(value.contains, key);
|
return this.in(value.contains, key);
|
||||||
}
|
}
|
||||||
return this.equals(key, value);
|
return this.equals(key, value);
|
||||||
})
|
}),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.flat()
|
.flat()
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Store, { CacheHandler } from '@ember-data/store';
|
||||||
|
import RequestManager from '@ember-data/request';
|
||||||
|
import { LegacyNetworkHandler } from '@ember-data/legacy-compat';
|
||||||
|
|
||||||
|
export default class extends Store {
|
||||||
|
requestManager = new RequestManager();
|
||||||
|
|
||||||
|
constructor(args) {
|
||||||
|
super(args);
|
||||||
|
|
||||||
|
this.requestManager.use([LegacyNetworkHandler]);
|
||||||
|
this.requestManager.useCache(CacheHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Transform from '@ember-data/serializer/transform';
|
||||||
|
import { TrackedObject } from 'tracked-built-ins';
|
||||||
|
|
||||||
|
export default class ObjectTransform extends Transform {
|
||||||
|
/**
|
||||||
|
* @param serialized
|
||||||
|
* @returns {object}
|
||||||
|
*/
|
||||||
|
deserialize(serialized) {
|
||||||
|
const obj = new TrackedObject(serialized || {});
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param deserialized
|
||||||
|
* @returns {object}
|
||||||
|
*/
|
||||||
|
serialize(deserialized) {
|
||||||
|
if (!deserialized) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return deserialized;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a POJO representing a filter query and converts it to an
|
||||||
|
* MQL expression string which is understood by the client daemon.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const filter = generateMQLFilterExpression({
|
||||||
|
* name: [{ contains: 'search text' }],
|
||||||
|
* scope: [{ equals: 'scope1'}, { equals: 'scope2' }],
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* // (name % "search text") and (scope_id = "scope1" or scope_id = "scope2")
|
||||||
|
*/
|
||||||
|
export function generateMQLFilterExpression(filterObj) {
|
||||||
|
if (!filterObj) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const expressions = Object.entries(filterObj)
|
||||||
|
.map(([key, filterObjValue]) => {
|
||||||
|
const filterValueArray = Array.isArray(filterObjValue)
|
||||||
|
? filterObjValue
|
||||||
|
: filterObjValue.values;
|
||||||
|
|
||||||
|
let clauses;
|
||||||
|
const filterValues = filterValueArray.map((filterObjValue) => {
|
||||||
|
if (!filterObjValue) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [operation, value] = Object.entries(filterObjValue)[0];
|
||||||
|
|
||||||
|
switch (operation) {
|
||||||
|
case 'contains':
|
||||||
|
return contains(key, value);
|
||||||
|
case 'gt':
|
||||||
|
return gt(key, value);
|
||||||
|
case 'gte':
|
||||||
|
return gte(key, value);
|
||||||
|
case 'lt':
|
||||||
|
return lt(key, value);
|
||||||
|
case 'lte':
|
||||||
|
return lte(key, value);
|
||||||
|
case 'notEquals':
|
||||||
|
return notEquals(key, value);
|
||||||
|
default:
|
||||||
|
return equals(key, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Default to `or` if we don't have a logical operator
|
||||||
|
const { logicalOperator } = filterObjValue;
|
||||||
|
if (logicalOperator === 'and') {
|
||||||
|
clauses = and(filterValues);
|
||||||
|
} else {
|
||||||
|
clauses = or(filterValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parenthetical(clauses);
|
||||||
|
})
|
||||||
|
.filter((item) => item);
|
||||||
|
return and(expressions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a POJO representing a search query and converts it to an
|
||||||
|
* MQL expression string which is understood by the client daemon.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const search = generateMQLSearchExpression({
|
||||||
|
* text: 'search',
|
||||||
|
* fields: ['id', 'name', 'description']
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* // (id % 'search' or name % 'search' or description % 'search')
|
||||||
|
*/
|
||||||
|
export function generateMQLSearchExpression(searchObj) {
|
||||||
|
if (!searchObj) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { text, fields } = searchObj;
|
||||||
|
|
||||||
|
return parenthetical(
|
||||||
|
or(fields.map((field) => contains(field, text)).filter((item) => item)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the MQL expression when a user passes in both search and filters.
|
||||||
|
*/
|
||||||
|
export function generateMQLExpression(obj) {
|
||||||
|
const { search, filters } = obj;
|
||||||
|
|
||||||
|
const expressions = [
|
||||||
|
generateMQLSearchExpression(search),
|
||||||
|
generateMQLFilterExpression(filters),
|
||||||
|
].filter((item) => item);
|
||||||
|
|
||||||
|
return and(expressions);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isEmpty = (input) =>
|
||||||
|
input === null || input === undefined || input === '';
|
||||||
|
|
||||||
|
// Escape any double quotes or backslashes and add quotes if it's a string
|
||||||
|
const sanitize = (input) =>
|
||||||
|
typeof input === 'string' ? `"${input?.replace(/(["\\])/g, '\\$1')}"` : input;
|
||||||
|
|
||||||
|
// Comparison Operators
|
||||||
|
const equals = (key, value) =>
|
||||||
|
!isEmpty(value) ? `${key} = ${sanitize(value)}` : null;
|
||||||
|
|
||||||
|
const notEquals = (key, value) =>
|
||||||
|
!isEmpty(value) ? `${key} != ${sanitize(value)}` : null;
|
||||||
|
|
||||||
|
const contains = (key, value) =>
|
||||||
|
!isEmpty(value) ? `${key} % ${sanitize(value)}` : null;
|
||||||
|
|
||||||
|
const gt = (key, value) =>
|
||||||
|
!isEmpty(value) ? `${key} > ${sanitize(value)}` : null;
|
||||||
|
|
||||||
|
const gte = (key, value) =>
|
||||||
|
!isEmpty(value) ? `${key} >= ${sanitize(value)}` : null;
|
||||||
|
|
||||||
|
const lt = (key, value) =>
|
||||||
|
!isEmpty(value) ? `${key} < ${sanitize(value)}` : null;
|
||||||
|
|
||||||
|
const lte = (key, value) =>
|
||||||
|
!isEmpty(value) ? `${key} <= ${sanitize(value)}` : null;
|
||||||
|
|
||||||
|
// Logical Operators
|
||||||
|
const and = (clauses) => clauses.join(' and ');
|
||||||
|
|
||||||
|
const or = (clauses) => clauses.join(' or ');
|
||||||
|
|
||||||
|
const parenthetical = (expression) => (expression ? `(${expression})` : null);
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { default } from 'api/abilities/policy';
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { default } from 'api/abilities/scope';
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { default } from 'api/handlers/client-daemon-handler';
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { default } from 'api/models/alias';
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { default } from 'api/models/policy';
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { default } from 'api/serializers/channel-recording';
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { default } from 'api/serializers/scope';
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { default } from 'api/services/store';
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { default } from 'api/transforms/object';
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { default } from 'api/utils/mql-query';
|
||||||
+115
-37
@@ -73,8 +73,12 @@ function routes() {
|
|||||||
return scope.scope ? scope.scope.id === scope_id : false;
|
return scope.scope ? scope.scope.id === scope_id : false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return resultSet.filter(makeBooleanFilter(filter));
|
const filteredResultSet = resultSet.filter(makeBooleanFilter(filter));
|
||||||
}
|
// add a response_type to the response to simulate pagination
|
||||||
|
// without having response_type, the unsupported controller modal
|
||||||
|
// will show when running with mirage
|
||||||
|
return { items: filteredResultSet.models, response_type: 'complete' };
|
||||||
|
},
|
||||||
);
|
);
|
||||||
this.post('/scopes', function ({ scopes }) {
|
this.post('/scopes', function ({ scopes }) {
|
||||||
// Parent scope comes through the payload via `scope_id`, but this needs
|
// Parent scope comes through the payload via `scope_id`, but this needs
|
||||||
@@ -88,7 +92,29 @@ function routes() {
|
|||||||
this.get('/scopes/:id');
|
this.get('/scopes/:id');
|
||||||
this.patch('/scopes/:id');
|
this.patch('/scopes/:id');
|
||||||
this.del('/scopes/:id');
|
this.del('/scopes/:id');
|
||||||
|
this.post(
|
||||||
|
'/scopes/:idMethod',
|
||||||
|
function ({ scopes }, { params: { idMethod } }) {
|
||||||
|
const attrs = this.normalizedRequestAttrs();
|
||||||
|
const id = idMethod.split(':')[0];
|
||||||
|
const method = idMethod.split(':')[1];
|
||||||
|
const scope = scopes.find(id);
|
||||||
|
|
||||||
|
const updatedAttrs = {
|
||||||
|
version: attrs.version,
|
||||||
|
storagePolicyId: attrs.storagePolicyId,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (method === 'attach-storage-policy') {
|
||||||
|
updatedAttrs.storagePolicyId = attrs.storagePolicyId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method === 'detach-storage-policy') {
|
||||||
|
updatedAttrs.storagePolicyId = '';
|
||||||
|
}
|
||||||
|
return scope.update(updatedAttrs);
|
||||||
|
},
|
||||||
|
);
|
||||||
// Auth & IAM resources
|
// Auth & IAM resources
|
||||||
|
|
||||||
this.get(
|
this.get(
|
||||||
@@ -107,11 +133,11 @@ function routes() {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
resultSet = authMethods.where(
|
resultSet = authMethods.where(
|
||||||
(authMethod) => authMethod.scopeId === scope_id
|
(authMethod) => authMethod.scopeId === scope_id,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return resultSet.filter(makeBooleanFilter(filter));
|
return resultSet.filter(makeBooleanFilter(filter));
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.post('/auth-methods', function ({ authMethods }) {
|
this.post('/auth-methods', function ({ authMethods }) {
|
||||||
const attrs = this.normalizedRequestAttrs();
|
const attrs = this.normalizedRequestAttrs();
|
||||||
@@ -130,7 +156,7 @@ function routes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return authMethods.find(id).update(attrs);
|
return authMethods.find(id).update(attrs);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.del('/auth-methods/:id', ({ authMethods }, { params: { id } }) => {
|
this.del('/auth-methods/:id', ({ authMethods }, { params: { id } }) => {
|
||||||
const authMethod = authMethods.find(id);
|
const authMethod = authMethods.find(id);
|
||||||
@@ -149,7 +175,7 @@ function routes() {
|
|||||||
'/accounts',
|
'/accounts',
|
||||||
(
|
(
|
||||||
{ accounts },
|
{ accounts },
|
||||||
{ queryParams: { auth_method_id: authMethodId, filter } }
|
{ queryParams: { auth_method_id: authMethodId, filter } },
|
||||||
) => {
|
) => {
|
||||||
let resultSet;
|
let resultSet;
|
||||||
if (authMethodId) {
|
if (authMethodId) {
|
||||||
@@ -158,7 +184,7 @@ function routes() {
|
|||||||
resultSet = accounts.all();
|
resultSet = accounts.all();
|
||||||
}
|
}
|
||||||
return resultSet.filter(makeBooleanFilter(filter));
|
return resultSet.filter(makeBooleanFilter(filter));
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.post('/accounts');
|
this.post('/accounts');
|
||||||
this.get('/accounts/:id');
|
this.get('/accounts/:id');
|
||||||
@@ -184,7 +210,7 @@ function routes() {
|
|||||||
updatedAttrs.attributes.password = attrs.new_password;
|
updatedAttrs.attributes.password = attrs.new_password;
|
||||||
}
|
}
|
||||||
return account.update(updatedAttrs);
|
return account.update(updatedAttrs);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Authenticate + auth methods custom routes
|
// Authenticate + auth methods custom routes
|
||||||
@@ -211,7 +237,7 @@ function routes() {
|
|||||||
resultSet = users.where((user) => user.scopeId === scope_id);
|
resultSet = users.where((user) => user.scopeId === scope_id);
|
||||||
}
|
}
|
||||||
return resultSet.filter(makeBooleanFilter(filter));
|
return resultSet.filter(makeBooleanFilter(filter));
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.post('/users');
|
this.post('/users');
|
||||||
this.get('/users/:id');
|
this.get('/users/:id');
|
||||||
@@ -262,7 +288,7 @@ function routes() {
|
|||||||
resultSet = groups.where((group) => group.scopeId === scope_id);
|
resultSet = groups.where((group) => group.scopeId === scope_id);
|
||||||
}
|
}
|
||||||
return resultSet.filter(makeBooleanFilter(filter));
|
return resultSet.filter(makeBooleanFilter(filter));
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.post('/groups');
|
this.post('/groups');
|
||||||
this.get('/groups/:id');
|
this.get('/groups/:id');
|
||||||
@@ -294,7 +320,7 @@ function routes() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return group.update(updatedAttrs);
|
return group.update(updatedAttrs);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// IAM: Roles
|
// IAM: Roles
|
||||||
@@ -309,7 +335,7 @@ function routes() {
|
|||||||
'/roles/:idMethod',
|
'/roles/:idMethod',
|
||||||
function (
|
function (
|
||||||
{ roles, users, groups, managedGroups },
|
{ roles, users, groups, managedGroups },
|
||||||
{ params: { idMethod } }
|
{ params: { idMethod } },
|
||||||
) {
|
) {
|
||||||
const attrs = this.normalizedRequestAttrs();
|
const attrs = this.normalizedRequestAttrs();
|
||||||
const id = idMethod.split(':')[0];
|
const id = idMethod.split(':')[0];
|
||||||
@@ -361,7 +387,7 @@ function routes() {
|
|||||||
updatedAttrs.managedGroupIds = updatedAttrs.managedGroupIds.filter(
|
updatedAttrs.managedGroupIds = updatedAttrs.managedGroupIds.filter(
|
||||||
(id) => {
|
(id) => {
|
||||||
return !attrs.principalIds.includes(id);
|
return !attrs.principalIds.includes(id);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,7 +399,7 @@ function routes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return role.update(updatedAttrs);
|
return role.update(updatedAttrs);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Other resources
|
// Other resources
|
||||||
@@ -383,7 +409,7 @@ function routes() {
|
|||||||
'/host-catalogs',
|
'/host-catalogs',
|
||||||
({ hostCatalogs }, { queryParams: { scope_id: scopeId } }) => {
|
({ hostCatalogs }, { queryParams: { scope_id: scopeId } }) => {
|
||||||
return hostCatalogs.where({ scopeId });
|
return hostCatalogs.where({ scopeId });
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.post(
|
this.post(
|
||||||
'/host-catalogs',
|
'/host-catalogs',
|
||||||
@@ -396,7 +422,7 @@ function routes() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
return hostCatalogs.create(attrs);
|
return hostCatalogs.create(attrs);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.get('/host-catalogs/:id');
|
this.get('/host-catalogs/:id');
|
||||||
this.patch('/host-catalogs/:id');
|
this.patch('/host-catalogs/:id');
|
||||||
@@ -408,7 +434,7 @@ function routes() {
|
|||||||
'/hosts',
|
'/hosts',
|
||||||
function ({ hosts }, { queryParams: { host_catalog_id: hostCatalogId } }) {
|
function ({ hosts }, { queryParams: { host_catalog_id: hostCatalogId } }) {
|
||||||
return hosts.where({ hostCatalogId });
|
return hosts.where({ hostCatalogId });
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.post('/hosts', function ({ hostCatalogs, hosts }) {
|
this.post('/hosts', function ({ hostCatalogs, hosts }) {
|
||||||
const attrs = this.normalizedRequestAttrs();
|
const attrs = this.normalizedRequestAttrs();
|
||||||
@@ -426,10 +452,10 @@ function routes() {
|
|||||||
'/host-sets',
|
'/host-sets',
|
||||||
function (
|
function (
|
||||||
{ hostSets },
|
{ hostSets },
|
||||||
{ queryParams: { host_catalog_id: hostCatalogId } }
|
{ queryParams: { host_catalog_id: hostCatalogId } },
|
||||||
) {
|
) {
|
||||||
return hostSets.where({ hostCatalogId });
|
return hostSets.where({ hostCatalogId });
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
this.post('/host-sets', function ({ hostCatalogs, hostSets }) {
|
this.post('/host-sets', function ({ hostCatalogs, hostSets }) {
|
||||||
@@ -477,7 +503,7 @@ function routes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return hostSet.update(updatedAttrs);
|
return hostSet.update(updatedAttrs);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// target
|
// target
|
||||||
@@ -500,7 +526,7 @@ function routes() {
|
|||||||
resultSet = targets.where((target) => target.scopeId === scope_id);
|
resultSet = targets.where((target) => target.scopeId === scope_id);
|
||||||
}
|
}
|
||||||
return resultSet.filter(makeBooleanFilter(filter));
|
return resultSet.filter(makeBooleanFilter(filter));
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.post('/targets', function ({ targets }) {
|
this.post('/targets', function ({ targets }) {
|
||||||
const attrs = this.normalizedRequestAttrs();
|
const attrs = this.normalizedRequestAttrs();
|
||||||
@@ -548,7 +574,7 @@ function routes() {
|
|||||||
resultSet = sessions.where((session) => session.scopeId === scope_id);
|
resultSet = sessions.where((session) => session.scopeId === scope_id);
|
||||||
}
|
}
|
||||||
return resultSet.filter(makeBooleanFilter(filter));
|
return resultSet.filter(makeBooleanFilter(filter));
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.get('/sessions/:id', function ({ sessions }, { params: { id } }) {
|
this.get('/sessions/:id', function ({ sessions }, { params: { id } }) {
|
||||||
const session = sessions.find(id);
|
const session = sessions.find(id);
|
||||||
@@ -573,7 +599,7 @@ function routes() {
|
|||||||
updatedAttrs.status = 'canceling';
|
updatedAttrs.status = 'canceling';
|
||||||
}
|
}
|
||||||
return session.update(updatedAttrs);
|
return session.update(updatedAttrs);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// auth-tokens
|
// auth-tokens
|
||||||
@@ -589,7 +615,7 @@ function routes() {
|
|||||||
this.get(
|
this.get(
|
||||||
'/credential-stores',
|
'/credential-stores',
|
||||||
({ credentialStores }, { queryParams: { scope_id: scopeId } }) =>
|
({ credentialStores }, { queryParams: { scope_id: scopeId } }) =>
|
||||||
credentialStores.where({ scopeId })
|
credentialStores.where({ scopeId }),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.get('/credential-stores/:id');
|
this.get('/credential-stores/:id');
|
||||||
@@ -603,8 +629,8 @@ function routes() {
|
|||||||
'/credential-libraries',
|
'/credential-libraries',
|
||||||
(
|
(
|
||||||
{ credentialLibraries },
|
{ credentialLibraries },
|
||||||
{ queryParams: { credential_store_id: credentialStoreId } }
|
{ queryParams: { credential_store_id: credentialStoreId } },
|
||||||
) => credentialLibraries.where({ credentialStoreId })
|
) => credentialLibraries.where({ credentialStoreId }),
|
||||||
);
|
);
|
||||||
this.get('/credential-libraries/:id');
|
this.get('/credential-libraries/:id');
|
||||||
this.post(
|
this.post(
|
||||||
@@ -614,7 +640,7 @@ function routes() {
|
|||||||
const credentialStore = credentialStores.find(attrs.credentialStoreId);
|
const credentialStore = credentialStores.find(attrs.credentialStoreId);
|
||||||
attrs.scopeId = credentialStore.scope.id;
|
attrs.scopeId = credentialStore.scope.id;
|
||||||
return credentialLibraries.create(attrs);
|
return credentialLibraries.create(attrs);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.del('/credential-libraries/:id');
|
this.del('/credential-libraries/:id');
|
||||||
this.patch('/credential-libraries/:id');
|
this.patch('/credential-libraries/:id');
|
||||||
@@ -625,8 +651,8 @@ function routes() {
|
|||||||
'/credentials',
|
'/credentials',
|
||||||
(
|
(
|
||||||
{ credentials },
|
{ credentials },
|
||||||
{ queryParams: { credential_store_id: credentialStoreId } }
|
{ queryParams: { credential_store_id: credentialStoreId } },
|
||||||
) => credentials.where({ credentialStoreId })
|
) => credentials.where({ credentialStoreId }),
|
||||||
);
|
);
|
||||||
this.get('/credentials/:id');
|
this.get('/credentials/:id');
|
||||||
this.post('/credentials', function ({ credentialStores, credentials }) {
|
this.post('/credentials', function ({ credentialStores, credentials }) {
|
||||||
@@ -644,7 +670,7 @@ function routes() {
|
|||||||
'/managed-groups',
|
'/managed-groups',
|
||||||
(
|
(
|
||||||
{ managedGroups },
|
{ managedGroups },
|
||||||
{ queryParams: { auth_method_id: authMethodId, filter } }
|
{ queryParams: { auth_method_id: authMethodId, filter } },
|
||||||
) => {
|
) => {
|
||||||
let resultSet;
|
let resultSet;
|
||||||
if (authMethodId) {
|
if (authMethodId) {
|
||||||
@@ -653,7 +679,7 @@ function routes() {
|
|||||||
resultSet = managedGroups.all();
|
resultSet = managedGroups.all();
|
||||||
}
|
}
|
||||||
return resultSet.filter(makeBooleanFilter(filter));
|
return resultSet.filter(makeBooleanFilter(filter));
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.post('/managed-groups');
|
this.post('/managed-groups');
|
||||||
this.get('/managed-groups/:id');
|
this.get('/managed-groups/:id');
|
||||||
@@ -665,7 +691,7 @@ function routes() {
|
|||||||
'/workers',
|
'/workers',
|
||||||
({ workers }, { queryParams: { scope_id: scopeId } }) => {
|
({ workers }, { queryParams: { scope_id: scopeId } }) => {
|
||||||
return workers.where({ scopeId });
|
return workers.where({ scopeId });
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.get('/workers/:id');
|
this.get('/workers/:id');
|
||||||
this.del('/workers/:id');
|
this.del('/workers/:id');
|
||||||
@@ -689,7 +715,7 @@ function routes() {
|
|||||||
return storageBuckets.all();
|
return storageBuckets.all();
|
||||||
}
|
}
|
||||||
return storageBuckets.where({ scopeId });
|
return storageBuckets.where({ scopeId });
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.get('/storage-buckets/:id');
|
this.get('/storage-buckets/:id');
|
||||||
this.del('/storage-buckets/:id');
|
this.del('/storage-buckets/:id');
|
||||||
@@ -708,21 +734,53 @@ function routes() {
|
|||||||
delete attrs.secrets;
|
delete attrs.secrets;
|
||||||
|
|
||||||
return storageBuckets.create(attrs);
|
return storageBuckets.create(attrs);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//storage-policy
|
||||||
|
this.get(
|
||||||
|
'/policies',
|
||||||
|
({ policies }, { queryParams: { scope_id: scopeId } }) => {
|
||||||
|
return policies.where({ scopeId });
|
||||||
|
},
|
||||||
|
);
|
||||||
|
this.get('/policies/:id');
|
||||||
|
this.del('/policies/:id');
|
||||||
|
this.patch('/policies/:id');
|
||||||
|
this.post('/policies', function ({ policies }) {
|
||||||
|
const attrs = this.normalizedRequestAttrs();
|
||||||
|
|
||||||
|
return policies.create(attrs);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Alias
|
||||||
|
this.get(
|
||||||
|
'/aliases',
|
||||||
|
({ aliases }, { queryParams: { scope_id: scopeId } }) => {
|
||||||
|
return aliases.where({ scopeId });
|
||||||
|
},
|
||||||
|
);
|
||||||
|
this.get('/aliases/:id');
|
||||||
|
this.del('/aliases/:id');
|
||||||
|
this.patch('/aliases/:id');
|
||||||
|
this.post('/aliases', function ({ aliases }) {
|
||||||
|
const attrs = this.normalizedRequestAttrs();
|
||||||
|
|
||||||
|
return aliases.create(attrs);
|
||||||
|
});
|
||||||
|
|
||||||
// session recordings
|
// session recordings
|
||||||
this.get(
|
this.get(
|
||||||
'/session-recordings',
|
'/session-recordings',
|
||||||
(
|
(
|
||||||
{ sessionRecordings },
|
{ sessionRecordings },
|
||||||
{ queryParams: { scope_id: scopeId, recursive } }
|
{ queryParams: { scope_id: scopeId, recursive } },
|
||||||
) => {
|
) => {
|
||||||
if (recursive && scopeId === 'global') {
|
if (recursive && scopeId === 'global') {
|
||||||
return sessionRecordings.all();
|
return sessionRecordings.all();
|
||||||
}
|
}
|
||||||
return sessionRecordings.where({ scopeId });
|
return sessionRecordings.where({ scopeId });
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.get(
|
this.get(
|
||||||
'/session-recordings/:idMethod',
|
'/session-recordings/:idMethod',
|
||||||
@@ -735,9 +793,29 @@ function routes() {
|
|||||||
} else {
|
} else {
|
||||||
return sessionRecordings.find(id);
|
return sessionRecordings.find(id);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.post(
|
||||||
|
'/session-recordings/:idMethod',
|
||||||
|
function ({ sessionRecordings }, { params: { idMethod } }) {
|
||||||
|
const attrs = this.normalizedRequestAttrs();
|
||||||
|
const id = idMethod.split(':')[0];
|
||||||
|
const method = idMethod.split(':')[1];
|
||||||
|
const record = sessionRecordings.find(id);
|
||||||
|
const updatedAttrs = {
|
||||||
|
version: attrs.version,
|
||||||
|
};
|
||||||
|
if (method === 'reapply-storage-policy') {
|
||||||
|
updatedAttrs.retain_until = faker.date.recent();
|
||||||
|
updatedAttrs.delete_after = faker.date.recent();
|
||||||
|
}
|
||||||
|
return record.update(updatedAttrs);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
this.del('/session-recordings/:id');
|
||||||
|
|
||||||
/* Uncomment the following line and the Response import above
|
/* Uncomment the following line and the Response import above
|
||||||
* Then change the response code to simulate error responses.
|
* Then change the response code to simulate error responses.
|
||||||
* this.get('/scopes', () => new Response(505));
|
* this.get('/scopes', () => new Response(505));
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import factory from '../generated/factories/alias';
|
||||||
|
import permissions from '../helpers/permissions';
|
||||||
|
import generateId from '../helpers/id';
|
||||||
|
|
||||||
|
const destinationIDs = ['', generateId('t_')];
|
||||||
|
|
||||||
|
export default factory.extend({
|
||||||
|
id: () => generateId('alt_'),
|
||||||
|
destination_id: (i) => destinationIDs[i % destinationIDs.length],
|
||||||
|
authorized_actions: () =>
|
||||||
|
permissions.authorizedActionsFor('alias') || [
|
||||||
|
'no-op',
|
||||||
|
'read',
|
||||||
|
'update',
|
||||||
|
'delete',
|
||||||
|
],
|
||||||
|
});
|
||||||
@@ -11,12 +11,18 @@ import {
|
|||||||
TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
|
TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
|
||||||
TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE,
|
TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE,
|
||||||
TYPES_CREDENTIAL_LIBRARY,
|
TYPES_CREDENTIAL_LIBRARY,
|
||||||
|
options,
|
||||||
} from 'api/models/credential-library';
|
} from 'api/models/credential-library';
|
||||||
|
|
||||||
export default factory.extend({
|
export default factory.extend({
|
||||||
id: () => generateId('cl_'),
|
id: () => generateId('cl_'),
|
||||||
type: (i) => TYPES_CREDENTIAL_LIBRARY[i % TYPES_CREDENTIAL_LIBRARY.length],
|
type: (i) => TYPES_CREDENTIAL_LIBRARY[i % TYPES_CREDENTIAL_LIBRARY.length],
|
||||||
|
|
||||||
|
credential_type(i) {
|
||||||
|
if (this.type === TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC) {
|
||||||
|
return options.credential_types[i % options.credential_types.length];
|
||||||
|
}
|
||||||
|
},
|
||||||
authorized_actions: () =>
|
authorized_actions: () =>
|
||||||
permissions.authorizedActionsFor('credential-library') || [
|
permissions.authorizedActionsFor('credential-library') || [
|
||||||
'no-op',
|
'no-op',
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export default factory.extend({
|
|||||||
return {
|
return {
|
||||||
disable_credential_rotation: faker.datatype.boolean(),
|
disable_credential_rotation: faker.datatype.boolean(),
|
||||||
region: `us-${faker.location.cardinalDirection()}-${faker.number.int(
|
region: `us-${faker.location.cardinalDirection()}-${faker.number.int(
|
||||||
9
|
9,
|
||||||
)}`,
|
)}`,
|
||||||
};
|
};
|
||||||
case 'azure':
|
case 'azure':
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import factory from '../generated/factories/policy';
|
||||||
|
import permissions from '../helpers/permissions';
|
||||||
|
import { faker } from '@faker-js/faker';
|
||||||
|
import generateId from '../helpers/id';
|
||||||
|
|
||||||
|
export default factory.extend({
|
||||||
|
id: () => generateId('pst_'),
|
||||||
|
|
||||||
|
authorized_actions: () =>
|
||||||
|
permissions.authorizedActionsFor('policy') || [
|
||||||
|
'no-op',
|
||||||
|
'read',
|
||||||
|
'update',
|
||||||
|
'delete',
|
||||||
|
],
|
||||||
|
|
||||||
|
attributes() {
|
||||||
|
return {
|
||||||
|
retain_for: {
|
||||||
|
days: faker.number.int({ min: 10, max: 100 }),
|
||||||
|
overridable: faker.datatype.boolean(),
|
||||||
|
},
|
||||||
|
|
||||||
|
delete_after: {
|
||||||
|
days: faker.number.int({ min: 101, max: 500 }),
|
||||||
|
overridable: faker.datatype.boolean(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -21,8 +21,8 @@ export default factory.extend({
|
|||||||
],
|
],
|
||||||
// eslint-disable-next-line ember/avoid-leaking-state-in-ember-objects
|
// eslint-disable-next-line ember/avoid-leaking-state-in-ember-objects
|
||||||
grant_strings: () => [
|
grant_strings: () => [
|
||||||
'id=*;action=*',
|
'ids=*;action=*',
|
||||||
'id=*;type=host-catalog;actions=create,read',
|
'ids=*;type=host-catalog;actions=create,read',
|
||||||
],
|
],
|
||||||
|
|
||||||
id: () => generateId('r_'),
|
id: () => generateId('r_'),
|
||||||
|
|||||||
@@ -11,13 +11,20 @@ import generateId from '../helpers/id';
|
|||||||
export default factory.extend({
|
export default factory.extend({
|
||||||
type: 'global',
|
type: 'global',
|
||||||
|
|
||||||
authorized_actions: () =>
|
authorized_actions() {
|
||||||
permissions.authorizedActionsFor('scope') || [
|
const authorizedActions = ['no-op', 'read', 'update'];
|
||||||
'no-op',
|
|
||||||
'read',
|
// Storage policies can only be attatched to global and org scopes.
|
||||||
'update',
|
if (this.type === 'global' || this.type === 'org') {
|
||||||
'delete',
|
authorizedActions.push('attach-storage-policy', 'detach-storage-policy');
|
||||||
],
|
}
|
||||||
|
|
||||||
|
if (this.type === 'org' || this.type === 'project') {
|
||||||
|
authorizedActions.push('delete');
|
||||||
|
}
|
||||||
|
|
||||||
|
return permissions.authorizedActionsFor('scope') || authorizedActions;
|
||||||
|
},
|
||||||
|
|
||||||
authorized_collection_actions() {
|
authorized_collection_actions() {
|
||||||
const collectionActions = {
|
const collectionActions = {
|
||||||
@@ -26,17 +33,19 @@ export default factory.extend({
|
|||||||
roles: ['create', 'list'],
|
roles: ['create', 'list'],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Worker permissions only available on the global scope
|
// Resources that are available only on the global scope
|
||||||
if (this.type === 'global') {
|
if (this.type === 'global') {
|
||||||
collectionActions.workers = ['create:worker-led', 'list'];
|
collectionActions.workers = ['create:worker-led', 'list'];
|
||||||
|
collectionActions.aliases = ['create', 'list'];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Session recording resources are only available on global or org scope
|
// Resources that are only available on the global or the org scope
|
||||||
if (this.type === 'global' || this.type === 'org') {
|
if (this.type === 'global' || this.type === 'org') {
|
||||||
collectionActions['storage-buckets'] = ['create', 'list'];
|
collectionActions['storage-buckets'] = ['create', 'list'];
|
||||||
collectionActions['session-recordings'] = ['list'];
|
collectionActions['session-recordings'] = ['list'];
|
||||||
collectionActions.users = ['create', 'list'];
|
collectionActions.users = ['create', 'list'];
|
||||||
collectionActions['auth-methods'] = ['create', 'list'];
|
collectionActions['auth-methods'] = ['create', 'list'];
|
||||||
|
collectionActions['policies'] = ['create', 'list'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.type === 'project') {
|
if (this.type === 'project') {
|
||||||
@@ -61,7 +70,7 @@ export default factory.extend({
|
|||||||
type: 'org',
|
type: 'org',
|
||||||
scope: { id: record.id, type: record.type },
|
scope: { id: record.id, type: record.type },
|
||||||
},
|
},
|
||||||
'withChildren'
|
'withChildren',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (record.type === 'org') {
|
if (record.type === 'org') {
|
||||||
|
|||||||
@@ -43,11 +43,24 @@ export default factory.extend({
|
|||||||
: null;
|
: null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
retain_until() {
|
||||||
|
return this.state === STATE_SESSION_RECORDING_AVAILABLE
|
||||||
|
? faker.date.recent()
|
||||||
|
: null;
|
||||||
|
},
|
||||||
|
delete_after() {
|
||||||
|
return this.state === STATE_SESSION_RECORDING_AVAILABLE
|
||||||
|
? faker.date.recent()
|
||||||
|
: null;
|
||||||
|
},
|
||||||
|
|
||||||
authorized_actions: () =>
|
authorized_actions: () =>
|
||||||
permissions.authorizedActionsFor('session-recording') || [
|
permissions.authorizedActionsFor('session-recording') || [
|
||||||
'no-op',
|
'no-op',
|
||||||
'read',
|
'read',
|
||||||
'download',
|
'download',
|
||||||
|
'reapply-storage-policy',
|
||||||
|
'delete',
|
||||||
],
|
],
|
||||||
|
|
||||||
withNonExistingUserAndTarget: trait({
|
withNonExistingUserAndTarget: trait({
|
||||||
@@ -57,7 +70,8 @@ export default factory.extend({
|
|||||||
const session = pickRandomElement(server.schema.sessions.all().models);
|
const session = pickRandomElement(server.schema.sessions.all().models);
|
||||||
session.id = 'deleted_session';
|
session.id = 'deleted_session';
|
||||||
const target = pickRandomElement(
|
const target = pickRandomElement(
|
||||||
server.schema.targets.where((target) => target.storage_bucket_id).models
|
server.schema.targets.where((target) => target.storage_bucket_id)
|
||||||
|
.models,
|
||||||
);
|
);
|
||||||
target.id = 'deleted_target';
|
target.id = 'deleted_target';
|
||||||
|
|
||||||
@@ -77,7 +91,8 @@ export default factory.extend({
|
|||||||
const user = pickRandomElement(server.schema.users.all().models);
|
const user = pickRandomElement(server.schema.users.all().models);
|
||||||
const session = pickRandomElement(server.schema.sessions.all().models);
|
const session = pickRandomElement(server.schema.sessions.all().models);
|
||||||
const target = pickRandomElement(
|
const target = pickRandomElement(
|
||||||
server.schema.targets.where((target) => target.storage_bucket_id).models
|
server.schema.targets.where((target) => target.storage_bucket_id)
|
||||||
|
.models,
|
||||||
);
|
);
|
||||||
|
|
||||||
sessionRecording.update({
|
sessionRecording.update({
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export default factory.extend({
|
|||||||
case TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3:
|
case TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3:
|
||||||
return {
|
return {
|
||||||
region: `us-${faker.location.cardinalDirection()}-${faker.number.int(
|
region: `us-${faker.location.cardinalDirection()}-${faker.number.int(
|
||||||
9
|
9,
|
||||||
)}`,
|
)}`,
|
||||||
disable_credential_rotation: faker.datatype.boolean(),
|
disable_credential_rotation: faker.datatype.boolean(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export default factory.extend({
|
|||||||
|
|
||||||
randomlySelectedCredentialLibraries = server.schema.credentialLibraries
|
randomlySelectedCredentialLibraries = server.schema.credentialLibraries
|
||||||
.where(
|
.where(
|
||||||
(credentialLibrary) => credentialLibrary.scopeId === target.scope.id
|
(credentialLibrary) => credentialLibrary.scopeId === target.scope.id,
|
||||||
)
|
)
|
||||||
.models.filter(() => randomBoolean())
|
.models.filter(() => randomBoolean())
|
||||||
.map((cred) => cred.id);
|
.map((cred) => cred.id);
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Factory } from 'miragejs';
|
||||||
|
import { faker } from '@faker-js/faker';
|
||||||
|
import { TYPE_ALIAS_TARGET } from 'api/models/alias';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GeneratedAliasModelFactory
|
||||||
|
*/
|
||||||
|
export default Factory.extend({
|
||||||
|
name: () => faker.word.words(),
|
||||||
|
type: TYPE_ALIAS_TARGET,
|
||||||
|
value: () => faker.word.words(),
|
||||||
|
description: () => faker.word.words(),
|
||||||
|
created_time: () => faker.date.recent(),
|
||||||
|
updated_time: () => faker.date.recent(),
|
||||||
|
version: () => faker.number.int(),
|
||||||
|
});
|
||||||
@@ -42,6 +42,7 @@ export default Factory.extend({
|
|||||||
signing_algorithms: ['RS256', 'RS384'],
|
signing_algorithms: ['RS256', 'RS384'],
|
||||||
allowed_audiences: ['www.alice.com', 'www.alice.com/admin'],
|
allowed_audiences: ['www.alice.com', 'www.alice.com/admin'],
|
||||||
idp_ca_certs: ['certificate-1234', 'certificate-5678'],
|
idp_ca_certs: ['certificate-1234', 'certificate-5678'],
|
||||||
|
prompts: ['consent'],
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case TYPE_AUTH_METHOD_LDAP:
|
case TYPE_AUTH_METHOD_LDAP:
|
||||||
@@ -51,7 +52,7 @@ export default Factory.extend({
|
|||||||
certificates: [faker.string.alphanumeric(50)],
|
certificates: [faker.string.alphanumeric(50)],
|
||||||
client_certificate: faker.string.alphanumeric(50),
|
client_certificate: faker.string.alphanumeric(50),
|
||||||
client_certificate_key: `---Begin Certificate --- ${faker.string.alphanumeric(
|
client_certificate_key: `---Begin Certificate --- ${faker.string.alphanumeric(
|
||||||
170
|
170,
|
||||||
)} ---End Certificate ---`,
|
)} ---End Certificate ---`,
|
||||||
client_certificate_key_hmac: faker.string.alphanumeric(50),
|
client_certificate_key_hmac: faker.string.alphanumeric(50),
|
||||||
enable_groups: true,
|
enable_groups: true,
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Factory } from 'miragejs';
|
||||||
|
import { faker } from '@faker-js/faker';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GeneratedStoragePolicyModelFactory
|
||||||
|
*/
|
||||||
|
export default Factory.extend({
|
||||||
|
name: () => faker.word.words(),
|
||||||
|
type: 'storage',
|
||||||
|
description: () => faker.word.words(),
|
||||||
|
created_time: () => faker.date.recent(),
|
||||||
|
updated_time: () => faker.date.recent(),
|
||||||
|
version: () => faker.number.int(),
|
||||||
|
});
|
||||||
@@ -13,5 +13,6 @@ export default Factory.extend({
|
|||||||
type: 'tcp',
|
type: 'tcp',
|
||||||
created_time: () => faker.date.recent(),
|
created_time: () => faker.date.recent(),
|
||||||
updated_time: () => faker.date.recent(),
|
updated_time: () => faker.date.recent(),
|
||||||
|
expiration_time: () => faker.date.soon(),
|
||||||
version: () => faker.number.int(),
|
version: () => faker.number.int(),
|
||||||
});
|
});
|
||||||
@@ -22,6 +22,6 @@ export default Factory.extend({
|
|||||||
active_connection_count: () => faker.number.int(10),
|
active_connection_count: () => faker.number.int(10),
|
||||||
release_version: () =>
|
release_version: () =>
|
||||||
`Boundary v${faker.number.int(11)}.${faker.number.int(
|
`Boundary v${faker.number.int(11)}.${faker.number.int(
|
||||||
50
|
50,
|
||||||
)}.${faker.number.int(12)}`,
|
)}.${faker.number.int(12)}`,
|
||||||
});
|
});
|
||||||
@@ -39,7 +39,7 @@ export default function (prefix = '') {
|
|||||||
let result = '';
|
let result = '';
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
result = result.concat(
|
result = result.concat(
|
||||||
characters[Math.floor(random() * characters.length)]
|
characters[Math.floor(random() * characters.length)],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return prefix.concat(result);
|
return prefix.concat(result);
|
||||||
|
|||||||
@@ -35,13 +35,13 @@ class ToggledCapabilities {
|
|||||||
// Find the value of a pair with key `authorized_actions`
|
// Find the value of a pair with key `authorized_actions`
|
||||||
// Safe-ish when the item is not present
|
// Safe-ish when the item is not present
|
||||||
#rawAuthorizedActions = (this.#queryPairs.find(
|
#rawAuthorizedActions = (this.#queryPairs.find(
|
||||||
(item) => item[0] === 'authorized_actions'
|
(item) => item[0] === 'authorized_actions',
|
||||||
) || [])[1];
|
) || [])[1];
|
||||||
|
|
||||||
// Safe-ish when the value is not present
|
// Safe-ish when the value is not present
|
||||||
#authorizedActions =
|
#authorizedActions =
|
||||||
JSON.parse(
|
JSON.parse(
|
||||||
decodeURIComponent(this.#rawAuthorizedActions || '') || 'null'
|
decodeURIComponent(this.#rawAuthorizedActions || '') || 'null',
|
||||||
) || {};
|
) || {};
|
||||||
|
|
||||||
// =methods
|
// =methods
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { belongsTo } from 'miragejs';
|
||||||
|
import Model from './base';
|
||||||
|
|
||||||
|
export default Model.extend({
|
||||||
|
scope: belongsTo(),
|
||||||
|
});
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { belongsTo } from 'miragejs';
|
||||||
|
import Model from './base';
|
||||||
|
export default Model.extend({
|
||||||
|
scope: belongsTo(),
|
||||||
|
});
|
||||||
@@ -56,7 +56,7 @@ const commandHandlers = {
|
|||||||
last_used_time: '',
|
last_used_time: '',
|
||||||
expiration_time: '',
|
expiration_time: '',
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -82,7 +82,7 @@ const commandHandlers = {
|
|||||||
auth_url: 'https://www.duckduckgo.com',
|
auth_url: 'https://www.duckduckgo.com',
|
||||||
token_id: 'token_1234',
|
token_id: 'token_1234',
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
),
|
),
|
||||||
token: (_, scopeAttrs) => {
|
token: (_, scopeAttrs) => {
|
||||||
oidcAttemptCounter++;
|
oidcAttemptCounter++;
|
||||||
@@ -105,7 +105,7 @@ const commandHandlers = {
|
|||||||
last_used_time: '',
|
last_used_time: '',
|
||||||
expiration_time: '',
|
expiration_time: '',
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -115,7 +115,7 @@ const commandHandlers = {
|
|||||||
// Handles all custom methods on /auth-methods/:id route
|
// Handles all custom methods on /auth-methods/:id route
|
||||||
export function authHandler({ scopes, authMethods }, request) {
|
export function authHandler({ scopes, authMethods }, request) {
|
||||||
const [, id, method] = request.params.id_method.match(
|
const [, id, method] = request.params.id_method.match(
|
||||||
/(?<id>.[^:]*):(?<method>(.*))/
|
/(?<id>.[^:]*):(?<method>(.*))/,
|
||||||
);
|
);
|
||||||
const authMethod = authMethods.find(id);
|
const authMethod = authMethods.find(id);
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export function targetHandler({ targets }, { params: { idMethod } }) {
|
|||||||
if (selectedHostSourceIds) {
|
if (selectedHostSourceIds) {
|
||||||
const listOfHostSources = addToSourcesList(
|
const listOfHostSources = addToSourcesList(
|
||||||
originHostSetIds,
|
originHostSetIds,
|
||||||
selectedHostSourceIds
|
selectedHostSourceIds,
|
||||||
);
|
);
|
||||||
if (listOfHostSources?.length) {
|
if (listOfHostSources?.length) {
|
||||||
updatedAttrs.hostSetIds = listOfHostSources;
|
updatedAttrs.hostSetIds = listOfHostSources;
|
||||||
@@ -52,7 +52,7 @@ export function targetHandler({ targets }, { params: { idMethod } }) {
|
|||||||
if (selectedHostSourceIds) {
|
if (selectedHostSourceIds) {
|
||||||
const removedHostSources = removeFromSourcesList(
|
const removedHostSources = removeFromSourcesList(
|
||||||
originHostSetIds,
|
originHostSetIds,
|
||||||
selectedHostSourceIds
|
selectedHostSourceIds,
|
||||||
);
|
);
|
||||||
updatedAttrs.hostSetIds = removedHostSources;
|
updatedAttrs.hostSetIds = removedHostSources;
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ export function targetHandler({ targets }, { params: { idMethod } }) {
|
|||||||
if (selectedBrokeredCredentials) {
|
if (selectedBrokeredCredentials) {
|
||||||
const listOfBrokeredCredentialSources = addToSourcesList(
|
const listOfBrokeredCredentialSources = addToSourcesList(
|
||||||
originalBrokeredCredentials,
|
originalBrokeredCredentials,
|
||||||
selectedBrokeredCredentials
|
selectedBrokeredCredentials,
|
||||||
);
|
);
|
||||||
if (listOfBrokeredCredentialSources?.length) {
|
if (listOfBrokeredCredentialSources?.length) {
|
||||||
updatedAttrs.brokeredCredentialSourceIds =
|
updatedAttrs.brokeredCredentialSourceIds =
|
||||||
@@ -73,7 +73,7 @@ export function targetHandler({ targets }, { params: { idMethod } }) {
|
|||||||
if (selectedInjectedCredentials) {
|
if (selectedInjectedCredentials) {
|
||||||
const listOfInjectedCredentialSources = addToSourcesList(
|
const listOfInjectedCredentialSources = addToSourcesList(
|
||||||
originalInjectedCredentials,
|
originalInjectedCredentials,
|
||||||
selectedInjectedCredentials
|
selectedInjectedCredentials,
|
||||||
);
|
);
|
||||||
if (listOfInjectedCredentialSources?.length) {
|
if (listOfInjectedCredentialSources?.length) {
|
||||||
updatedAttrs.injectedApplicationCredentialSourceIds =
|
updatedAttrs.injectedApplicationCredentialSourceIds =
|
||||||
@@ -86,7 +86,7 @@ export function targetHandler({ targets }, { params: { idMethod } }) {
|
|||||||
if (selectedBrokeredCredentials) {
|
if (selectedBrokeredCredentials) {
|
||||||
const removedCredentialSources = removeFromSourcesList(
|
const removedCredentialSources = removeFromSourcesList(
|
||||||
originalBrokeredCredentials,
|
originalBrokeredCredentials,
|
||||||
selectedBrokeredCredentials
|
selectedBrokeredCredentials,
|
||||||
);
|
);
|
||||||
updatedAttrs.brokeredCredentialSourceIds = removedCredentialSources;
|
updatedAttrs.brokeredCredentialSourceIds = removedCredentialSources;
|
||||||
}
|
}
|
||||||
@@ -94,7 +94,7 @@ export function targetHandler({ targets }, { params: { idMethod } }) {
|
|||||||
if (selectedInjectedCredentials) {
|
if (selectedInjectedCredentials) {
|
||||||
const removedCredentialSources = removeFromSourcesList(
|
const removedCredentialSources = removeFromSourcesList(
|
||||||
originalInjectedCredentials,
|
originalInjectedCredentials,
|
||||||
selectedInjectedCredentials
|
selectedInjectedCredentials,
|
||||||
);
|
);
|
||||||
updatedAttrs.injectedApplicationCredentialSourceIds =
|
updatedAttrs.injectedApplicationCredentialSourceIds =
|
||||||
removedCredentialSources;
|
removedCredentialSources;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export default function (server) {
|
|||||||
type: 'org',
|
type: 'org',
|
||||||
scope: { id: globalScope.id, type: globalScope.type },
|
scope: { id: globalScope.id, type: globalScope.type },
|
||||||
},
|
},
|
||||||
'withChildren'
|
'withChildren',
|
||||||
)[0];
|
)[0];
|
||||||
|
|
||||||
// Auth
|
// Auth
|
||||||
@@ -29,13 +29,13 @@ export default function (server) {
|
|||||||
'auth-method',
|
'auth-method',
|
||||||
5,
|
5,
|
||||||
{ scope: globalScope },
|
{ scope: globalScope },
|
||||||
'withAccountsAndUsersAndManagedGroups'
|
'withAccountsAndUsersAndManagedGroups',
|
||||||
);
|
);
|
||||||
const orgAuthMethods = server.createList(
|
const orgAuthMethods = server.createList(
|
||||||
'auth-method',
|
'auth-method',
|
||||||
3,
|
3,
|
||||||
{ scope: orgScope },
|
{ scope: orgScope },
|
||||||
'withAccountsAndUsersAndManagedGroups'
|
'withAccountsAndUsersAndManagedGroups',
|
||||||
);
|
);
|
||||||
// Authenticated user/account
|
// Authenticated user/account
|
||||||
const user = server.create('user', {
|
const user = server.create('user', {
|
||||||
@@ -62,13 +62,13 @@ export default function (server) {
|
|||||||
'role',
|
'role',
|
||||||
1,
|
1,
|
||||||
{ scope: globalScope },
|
{ scope: globalScope },
|
||||||
'withPrincipals'
|
'withPrincipals',
|
||||||
);
|
);
|
||||||
//create managed groups for role/principals in globalScope
|
//create managed groups for role/principals in globalScope
|
||||||
globalScopeRoles.forEach((role) => {
|
globalScopeRoles.forEach((role) => {
|
||||||
const { scope } = role;
|
const { scope } = role;
|
||||||
const oidcAuthMethod = globalAuthMethods.filter(
|
const oidcAuthMethod = globalAuthMethods.filter(
|
||||||
(auth) => auth.type === TYPE_AUTH_METHOD_OIDC
|
(auth) => auth.type === TYPE_AUTH_METHOD_OIDC,
|
||||||
)[0];
|
)[0];
|
||||||
const { type } = oidcAuthMethod;
|
const { type } = oidcAuthMethod;
|
||||||
const managedGroups = server.createList('managed-group', 2, {
|
const managedGroups = server.createList('managed-group', 2, {
|
||||||
@@ -83,13 +83,13 @@ export default function (server) {
|
|||||||
'role',
|
'role',
|
||||||
5,
|
5,
|
||||||
{ scope: orgScope },
|
{ scope: orgScope },
|
||||||
'withPrincipals'
|
'withPrincipals',
|
||||||
);
|
);
|
||||||
//create managed groups for role/principals in orgScope
|
//create managed groups for role/principals in orgScope
|
||||||
orgScopeRoles.forEach((role) => {
|
orgScopeRoles.forEach((role) => {
|
||||||
const { scope } = role;
|
const { scope } = role;
|
||||||
const oidcAuthMethod = orgAuthMethods.filter(
|
const oidcAuthMethod = orgAuthMethods.filter(
|
||||||
(auth) => auth.type === TYPE_AUTH_METHOD_OIDC
|
(auth) => auth.type === TYPE_AUTH_METHOD_OIDC,
|
||||||
)[0];
|
)[0];
|
||||||
const { type } = oidcAuthMethod;
|
const { type } = oidcAuthMethod;
|
||||||
const managedGroups = server.createList('managed-group', 2, {
|
const managedGroups = server.createList('managed-group', 2, {
|
||||||
@@ -104,6 +104,13 @@ export default function (server) {
|
|||||||
server.createList('storage-bucket', 3, { scope: globalScope });
|
server.createList('storage-bucket', 3, { scope: globalScope });
|
||||||
server.createList('storage-bucket', 2, { scope: orgScope });
|
server.createList('storage-bucket', 2, { scope: orgScope });
|
||||||
|
|
||||||
|
// Storage Policies
|
||||||
|
server.createList('policy', 3, { scope: globalScope });
|
||||||
|
server.createList('policy', 3, { scope: orgScope });
|
||||||
|
|
||||||
|
// Aliases
|
||||||
|
server.createList('alias', 3, { scope: globalScope });
|
||||||
|
|
||||||
// Other resources
|
// Other resources
|
||||||
server.schema.scopes.where({ type: 'project' }).models.forEach((scope) => {
|
server.schema.scopes.where({ type: 'project' }).models.forEach((scope) => {
|
||||||
server.createList('host-catalog', 8, { scope }, 'withChildren');
|
server.createList('host-catalog', 8, { scope }, 'withChildren');
|
||||||
@@ -129,19 +136,19 @@ export default function (server) {
|
|||||||
3,
|
3,
|
||||||
{ scope: globalScope },
|
{ scope: globalScope },
|
||||||
'withConnectionAndChannels',
|
'withConnectionAndChannels',
|
||||||
'withExistingUserAndTarget'
|
'withExistingUserAndTarget',
|
||||||
);
|
);
|
||||||
server.create(
|
server.create(
|
||||||
'session-recording',
|
'session-recording',
|
||||||
{ scope: globalScope },
|
{ scope: globalScope },
|
||||||
'withConnectionAndChannels',
|
'withConnectionAndChannels',
|
||||||
'withNonExistingUserAndTarget'
|
'withNonExistingUserAndTarget',
|
||||||
);
|
);
|
||||||
server.createList(
|
server.createList(
|
||||||
'session-recording',
|
'session-recording',
|
||||||
2,
|
2,
|
||||||
{ scope: orgScope },
|
{ scope: orgScope },
|
||||||
'withConnectionAndChannels',
|
'withConnectionAndChannels',
|
||||||
'withExistingUserAndTarget'
|
'withExistingUserAndTarget',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -57,6 +57,7 @@ export default function initializeMockIPC(server, config) {
|
|||||||
userId: 'authenticateduser',
|
userId: 'authenticateduser',
|
||||||
type,
|
type,
|
||||||
created_time: new Date().toISOString(),
|
created_time: new Date().toISOString(),
|
||||||
|
expiration_time: faker.date.soon(),
|
||||||
});
|
});
|
||||||
const decoded = {
|
const decoded = {
|
||||||
key1: 'value 1',
|
key1: 'value 1',
|
||||||
@@ -178,6 +179,14 @@ export default function initializeMockIPC(server, config) {
|
|||||||
closeWindow() {}
|
closeWindow() {}
|
||||||
toggleFullscreenWindow() {}
|
toggleFullscreenWindow() {}
|
||||||
stop() {}
|
stop() {}
|
||||||
|
checkCommand() {
|
||||||
|
return faker.system.filePath();
|
||||||
|
}
|
||||||
|
addTokenToClientDaemon() {}
|
||||||
|
searchClientDaemon() {}
|
||||||
|
isClientDaemonRunning() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export default ApplicationSerializer.extend({
|
|||||||
_hashForModel(model) {
|
_hashForModel(model) {
|
||||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||||
this,
|
this,
|
||||||
arguments
|
arguments,
|
||||||
);
|
);
|
||||||
json.auth_method_id = model.authMethodId;
|
json.auth_method_id = model.authMethodId;
|
||||||
delete json.attributes?.password;
|
delete json.attributes?.password;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export default RestSerializer.extend({
|
|||||||
|
|
||||||
keyForRelationshipId(relationshipName) {
|
keyForRelationshipId(relationshipName) {
|
||||||
return `${this._container.inflector.singularize(
|
return `${this._container.inflector.singularize(
|
||||||
underscore(relationshipName)
|
underscore(relationshipName),
|
||||||
)}_id`;
|
)}_id`;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export default ApplicationSerializer.extend({
|
|||||||
_hashForModel(model) {
|
_hashForModel(model) {
|
||||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||||
this,
|
this,
|
||||||
arguments
|
arguments,
|
||||||
);
|
);
|
||||||
// If the scope marks this auth method as primary, designate it
|
// If the scope marks this auth method as primary, designate it
|
||||||
// as such with a read-only boolean field (this is how the API behaves).
|
// as such with a read-only boolean field (this is how the API behaves).
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export default ApplicationSerializer.extend({
|
|||||||
_hashForModel(model) {
|
_hashForModel(model) {
|
||||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||||
this,
|
this,
|
||||||
arguments
|
arguments,
|
||||||
);
|
);
|
||||||
const { channelRecordings } = this.schema;
|
const { channelRecordings } = this.schema;
|
||||||
if (model.channelRecordingIds) {
|
if (model.channelRecordingIds) {
|
||||||
|
|||||||
@@ -11,9 +11,20 @@ export default ApplicationSerializer.extend({
|
|||||||
_hashForModel(model) {
|
_hashForModel(model) {
|
||||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||||
this,
|
this,
|
||||||
arguments
|
arguments,
|
||||||
);
|
);
|
||||||
json.credential_store_id = model.credentialStoreId;
|
json.credential_store_id = model.credentialStoreId;
|
||||||
|
|
||||||
|
// BE API only updates these fields if there's an update mask, otherwise they remain unmodified
|
||||||
|
// but we don't need this flow in our mocks, so we are deleting fields with null value
|
||||||
|
|
||||||
|
if (json.credential_mapping_overrides) {
|
||||||
|
Object.keys(json.credential_mapping_overrides).forEach((key) => {
|
||||||
|
if (json.credential_mapping_overrides[key] === null) {
|
||||||
|
delete json.credential_mapping_overrides[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
return json;
|
return json;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -11,7 +11,7 @@ export default ApplicationSerializer.extend({
|
|||||||
_hashForModel(/* model */) {
|
_hashForModel(/* model */) {
|
||||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||||
this,
|
this,
|
||||||
arguments
|
arguments,
|
||||||
);
|
);
|
||||||
// in a real API, the following fields are set-only and returned in
|
// in a real API, the following fields are set-only and returned in
|
||||||
// associated HMAC fields
|
// associated HMAC fields
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export default ApplicationSerializer.extend({
|
|||||||
_hashForModel(model) {
|
_hashForModel(model) {
|
||||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||||
this,
|
this,
|
||||||
arguments
|
arguments,
|
||||||
);
|
);
|
||||||
json.credential_store_id = model.credentialStoreId;
|
json.credential_store_id = model.credentialStoreId;
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ export default ApplicationSerializer.extend({
|
|||||||
|
|
||||||
keyForRelationshipIds(relationshipName) {
|
keyForRelationshipIds(relationshipName) {
|
||||||
return `${this._container.inflector.singularize(
|
return `${this._container.inflector.singularize(
|
||||||
underscore(relationshipName)
|
underscore(relationshipName),
|
||||||
)}_ids`;
|
)}_ids`;
|
||||||
},
|
},
|
||||||
|
|
||||||
_hashForModel(model) {
|
_hashForModel(model) {
|
||||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||||
this,
|
this,
|
||||||
arguments
|
arguments,
|
||||||
);
|
);
|
||||||
if (model.memberIds.length) json.member_ids = model.memberIds;
|
if (model.memberIds.length) json.member_ids = model.memberIds;
|
||||||
return json;
|
return json;
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ export default ApplicationSerializer.extend({
|
|||||||
|
|
||||||
keyForRelationshipIds(relationshipName) {
|
keyForRelationshipIds(relationshipName) {
|
||||||
return `${this._container.inflector.singularize(
|
return `${this._container.inflector.singularize(
|
||||||
underscore(relationshipName)
|
underscore(relationshipName),
|
||||||
)}_ids`;
|
)}_ids`;
|
||||||
},
|
},
|
||||||
|
|
||||||
_hashForModel(model) {
|
_hashForModel(model) {
|
||||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||||
this,
|
this,
|
||||||
arguments
|
arguments,
|
||||||
);
|
);
|
||||||
json.host_catalog_id = model.hostCatalogId;
|
json.host_catalog_id = model.hostCatalogId;
|
||||||
if (model.hostIds?.length) {
|
if (model.hostIds?.length) {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export default ApplicationSerializer.extend({
|
|||||||
_hashForModel(model) {
|
_hashForModel(model) {
|
||||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||||
this,
|
this,
|
||||||
arguments
|
arguments,
|
||||||
);
|
);
|
||||||
json.host_catalog_id = model.hostCatalogId;
|
json.host_catalog_id = model.hostCatalogId;
|
||||||
return json;
|
return json;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export default ApplicationSerializer.extend({
|
|||||||
_hashForModel(model) {
|
_hashForModel(model) {
|
||||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||||
this,
|
this,
|
||||||
arguments
|
arguments,
|
||||||
);
|
);
|
||||||
json.auth_method_id = model.authMethodId;
|
json.auth_method_id = model.authMethodId;
|
||||||
return json;
|
return json;
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ApplicationSerializer from './application';
|
||||||
|
|
||||||
|
export default ApplicationSerializer.extend({
|
||||||
|
modelName: 'policy',
|
||||||
|
});
|
||||||
@@ -11,7 +11,7 @@ export default ApplicationSerializer.extend({
|
|||||||
_hashForModel(model) {
|
_hashForModel(model) {
|
||||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||||
this,
|
this,
|
||||||
arguments
|
arguments,
|
||||||
);
|
);
|
||||||
const serializedUsers = model.users.models.map((user) => ({
|
const serializedUsers = model.users.models.map((user) => ({
|
||||||
scope_id: model.scope.id,
|
scope_id: model.scope.id,
|
||||||
@@ -28,7 +28,7 @@ export default ApplicationSerializer.extend({
|
|||||||
scope_id: model.scope.id,
|
scope_id: model.scope.id,
|
||||||
id: managedGroup.id,
|
id: managedGroup.id,
|
||||||
type: 'managed group',
|
type: 'managed group',
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
json.principals = [
|
json.principals = [
|
||||||
...serializedUsers,
|
...serializedUsers,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export default ApplicationSerializer.extend({
|
|||||||
_hashForModel(model) {
|
_hashForModel(model) {
|
||||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||||
this,
|
this,
|
||||||
arguments
|
arguments,
|
||||||
);
|
);
|
||||||
const { connectionRecordings, scopes } = this.schema;
|
const { connectionRecordings, scopes } = this.schema;
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ export default ApplicationSerializer.extend({
|
|||||||
const connection = connectionRecordings.find(id);
|
const connection = connectionRecordings.find(id);
|
||||||
return ConnectionRecordingSerializer.prototype._hashForModel.apply(
|
return ConnectionRecordingSerializer.prototype._hashForModel.apply(
|
||||||
this,
|
this,
|
||||||
[connection]
|
[connection],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ export default ApplicationSerializer.extend({
|
|||||||
|
|
||||||
keyForRelationshipId(relationshipName) {
|
keyForRelationshipId(relationshipName) {
|
||||||
return `${this._container.inflector.singularize(
|
return `${this._container.inflector.singularize(
|
||||||
underscore(relationshipName)
|
underscore(relationshipName),
|
||||||
)}_id`;
|
)}_id`;
|
||||||
},
|
},
|
||||||
|
|
||||||
_hashForModel(model) {
|
_hashForModel(model) {
|
||||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||||
this,
|
this,
|
||||||
arguments
|
arguments,
|
||||||
);
|
);
|
||||||
json.user_id = model.userId;
|
json.user_id = model.userId;
|
||||||
json.target_id = model.targetId;
|
json.target_id = model.targetId;
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ export default ApplicationSerializer.extend({
|
|||||||
|
|
||||||
keyForRelationshipIds(relationshipName) {
|
keyForRelationshipIds(relationshipName) {
|
||||||
return `${this._container.inflector.singularize(
|
return `${this._container.inflector.singularize(
|
||||||
underscore(relationshipName)
|
underscore(relationshipName),
|
||||||
)}_ids`;
|
)}_ids`;
|
||||||
},
|
},
|
||||||
|
|
||||||
_hashForModel(model) {
|
_hashForModel(model) {
|
||||||
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
const json = ApplicationSerializer.prototype._hashForModel.apply(
|
||||||
this,
|
this,
|
||||||
arguments
|
arguments,
|
||||||
);
|
);
|
||||||
const { hostSets } = this.schema;
|
const { hostSets } = this.schema;
|
||||||
if (model.hostSetIds?.length) {
|
if (model.hostSetIds?.length) {
|
||||||
|
|||||||
Loaded 100 of 906 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user