Skip to content

Commit

Permalink
refactor: fixes and improves maintenance
Browse files Browse the repository at this point in the history
When we register a domain, we need to specify the org_id for the generated
identity; the org_id we use here must match the org_id used when generating the
token or the operation will fail with sign mismatching; now a ORG_ID environment
variable is used, that by default will be 12345 for better experience, but its
value can be override from the CLI.

This change additionally remove duplicated code and keep the scripts cleaner.
Bear in mind that 'curl.sh' wrapper prepare the request depending on the
environment variables if moving additional variables to the common scripts.

- Allows to customize ORG_ID variable; it could be helpful when checking data
  isolation.
- Allows to customize X_RH_IDENTITY and X_RH_FAKE_IDENTITY; it could be helpful
  when checking identity enforcement.
- Now the scripts can be invoked from anywhere in the repository.

Co-authored-by: Christian Heimes <[email protected]>
Signed-off-by: Alejandro Visiedo <[email protected]>
  • Loading branch information
avisiedo and tiran committed Sep 27, 2023
1 parent cbe1388 commit cb547b2
Show file tree
Hide file tree
Showing 22 changed files with 189 additions and 188 deletions.
49 changes: 49 additions & 0 deletions test/scripts/common.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#
# Include file with common parts shared for local and ephemeral
#

# Troubleshooting:
# - Run with DEBUG=1 to see some traces from curl.sh wrapper
# $ DEBUG=1 ./test/scripts/local-domain-token.sh
# - Run with more verbose by:
# $ DEBUG=1 bash -xv ./test/scripts/local-domain-token.sh

function error {
local err=$?
printf "ERROR: %s\n" "$*" >&2
exit $err
}

ORG_ID="${ORG_ID:-12345}"

export IDENTITY_USER="" # Use $(identity_user)
export IDENTITY_SYSTEM="" # Use $(identity_system)
export IDM_VERSION="" # Use $(idm_version)

SRCDIR="$(dirname "${BASH_SOURCE[0]}")"
# shellcheck disable=SC2034 # ignore unused variable
BASEDIR="$(dirname "$(dirname "${SRCDIR}")")"
REPOBASEDIR="$(git rev-parse --show-toplevel)"
export REPOBASEDIR
export XRHIDGEN="${REPOBASEDIR}/tools/bin/xrhidgen"

if [[ ! -x "${XRHIDGEN}" ]]; then
error "${XRHIDGEN} is missing, run 'make install-tools'"
exit 2
fi

function identity_user() {
"${XRHIDGEN}" -org-id "${ORG_ID}" user -is-active=true -is-org-admin=true -user-id test -username test | base64 -w0
}
export -f identity_user # Needed for making it available in sub-shells

function identity_system() {
"${XRHIDGEN}" -org-id "${ORG_ID}" system -cn "6f324116-b3d2-11ed-8a37-482ae3863d30" -cert-type system | base64 -w0
}
export -f identity_system # Needed for making it available in sub-shells

function idm_version() {
IDM_VERSION='{"ipa-hcc": "0.7", "ipa": "4.10.0-8.el9_1"}'
printf "%s" "${IDM_VERSION}"
}
export -f idm_version
23 changes: 7 additions & 16 deletions test/scripts/ephe-domains-delete.sh
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
#!/bin/bash
set -eo pipefail

function error {
local err=$?
printf "%s\n" "$1" >&2
exit $err
}

# make ephemeral-db-cli <<< "select domain_uuid from domains order by id desc limit 1;\\q"
# shellcheck disable=SC1091
source "$(dirname "${BASH_SOURCE[0]}")/ephe.inc"

UUID="$1"
[ "${UUID}" != "" ] || error "UUID is empty"

export NAMESPACE="$(oc project -q)"
CREDS="$( oc get secrets/env-${NAMESPACE}-keycloak -o jsonpath='{.data.defaultUsername}' | base64 -d )"
CREDS="${CREDS}:$( oc get secrets/env-${NAMESPACE}-keycloak -o jsonpath='{.data.defaultPassword}' | base64 -d )"
export CREDS

unset X_RH_IDENTITY
export X_RH_FAKE_IDENTITY="$( ./tools/bin/xrhidgen -org-id 12345 system -cn "6f324116-b3d2-11ed-8a37-482ae3863d30" -cert-type system | base64 -w0 )"
export X_RH_FAKE_IDENTITY="${X_RH_FAKE_IDENTITY:-$(identity_user)}"
export X_RH_IDM_REGISTRATION_TOKEN="${TOKEN}"
export X_RH_IDM_VERSION="$( base64 -w0 <<< '{"ipa-hcc": "0.7", "ipa": "4.10.0-8.el9_1"}' )"
BASE_URL="https://$( oc get routes -l app=idmsvc-backend -o jsonpath='{.items[0].spec.host}' )/api/idmsvc/v1"
./scripts/curl.sh -i -X DELETE "${BASE_URL}/domains/${UUID}"
X_RH_IDM_VERSION="$(idm_version)"
export X_RH_IDM_VERSION
"${REPOBASEDIR}/scripts/curl.sh" -i -X DELETE "${BASE_URL}/domains/${UUID}"
13 changes: 5 additions & 8 deletions test/scripts/ephe-domains-list.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
#!/bin/bash
set -eo pipefail

export NAMESPACE="$(oc project -q)"
CREDS="$( oc get secrets/env-${NAMESPACE}-keycloak -o jsonpath='{.data.defaultUsername}' | base64 -d )"
CREDS="${CREDS}:$( oc get secrets/env-${NAMESPACE}-keycloak -o jsonpath='{.data.defaultPassword}' | base64 -d )"
export CREDS
# shellcheck disable=SC1091
source "$(dirname "${BASH_SOURCE[0]}")/ephe.inc"

unset X_RH_IDENTITY
unset X_RH_FAKE_IDENTITY
BASE_URL="https://$( oc get routes -l app=idmsvc-backend -o jsonpath='{.items[0].spec.host}' )/api/idmsvc/v1"
./scripts/curl.sh -i "${BASE_URL}/domains"

export X_RH_FAKE_IDENTITY="${X_RH_FAKE_IDENTITY:-$(identity_user)}"
"${REPOBASEDIR}/scripts/curl.sh" -i "${BASE_URL}/domains"
23 changes: 7 additions & 16 deletions test/scripts/ephe-domains-patch.sh
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
#!/bin/bash
set -eo pipefail

function error {
local err=$?
printf "%s\n" "$1" >&2
exit $err
}

# make ephemeral-db-cli <<< "select domain_uuid from domains order by id desc limit 1;\\q"
# shellcheck disable=SC1091
source "$(dirname "${BASH_SOURCE[0]}")/ephe.inc"

UUID="$1"
[ "${UUID}" != "" ] || error "UUID is empty"

export NAMESPACE="$(oc project -q)"
CREDS="$( oc get secrets/env-${NAMESPACE}-keycloak -o jsonpath='{.data.defaultUsername}' | base64 -d )"
CREDS="${CREDS}:$( oc get secrets/env-${NAMESPACE}-keycloak -o jsonpath='{.data.defaultPassword}' | base64 -d )"
export CREDS

unset X_RH_IDENTITY
export X_RH_FAKE_IDENTITY="$( ./bin/xrhidgen -org-id 12345 system -cn "6f324116-b3d2-11ed-8a37-482ae3863d30" -cert-type system | base64 -w0 )"
export X_RH_FAKE_IDENTITY="${X_RH_FAKE_IDENTITY:-$(identity_user)}"
unset X_RH_IDM_REGISTRATION_TOKEN
export X_RH_IDM_VERSION='{"ipa-hcc": "0.9", "ipa": "4.10.0-8.el9_1", "os-release-id": "rhel", "os-release-version-id": "9.1"}'
BASE_URL="https://$( oc get routes -l app=idmsvc-backend -o jsonpath='{.items[0].spec.host}' )/api/idmsvc/v1"
./scripts/curl.sh -i -X PATCH -d @<( cat test/data/http/patch-rhel-idm-domain.json | sed -e "s/{{createDomain.response.body.domain_id}}/${UUID}/g" -e 's/{{subscription_manager_id}}/6f324116-b3d2-11ed-8a37-482ae3863d30/g' ) "${BASE_URL}/domains/${UUID}"
X_RH_IDM_VERSION="$(idm_version)"
export X_RH_IDM_VERSION
"${REPOBASEDIR}/scripts/curl.sh" -i -X PATCH -d @<(sed -e "s/{{createDomain.response.body.domain_id}}/${UUID}/g" -e 's/{{subscription_manager_id}}/6f324116-b3d2-11ed-8a37-482ae3863d30/g' < "${REPOBASEDIR}/test/data/http/patch-rhel-idm-domain.json") "${BASE_URL}/domains/${UUID}"
19 changes: 5 additions & 14 deletions test/scripts/ephe-domains-read.sh
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
#!/bin/bash
set -eo pipefail

function error {
local err=$?
printf "%s\n" "$1" >&2
exit $err
}
# shellcheck disable=SC1091
source "$(dirname "${BASH_SOURCE[0]}")/ephe.inc"

UUID="$1"
[ "${UUID}" != "" ] || error "UUID is empty"

export NAMESPACE="$(oc project -q)"
CREDS="$( oc get secrets/env-${NAMESPACE}-keycloak -o jsonpath='{.data.defaultUsername}' | base64 -d )"
CREDS="${CREDS}:$( oc get secrets/env-${NAMESPACE}-keycloak -o jsonpath='{.data.defaultPassword}' | base64 -d )"
export CREDS

unset X_RH_IDENTITY
unset X_RH_FAKE_IDENTITY
BASE_URL="https://$( oc get routes -l app=idmsvc-backend -o jsonpath='{.items[0].spec.host}' )/api/idmsvc/v1"

./scripts/curl.sh -i "${BASE_URL}/domains/${UUID}"
export X_RH_FAKE_IDENTITY="${X_RH_FAKE_IDENTITY:-$(identity_user)}"
"${REPOBASEDIR}/scripts/curl.sh" -i "${BASE_URL}/domains/${UUID}"
23 changes: 7 additions & 16 deletions test/scripts/ephe-domains-register.sh
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
#!/bin/bash
set -eo pipefail

function error {
local err=$?
printf "%s\n" "$1" >&2
exit $err
}

# ephe-domains-token.sh
# shellcheck disable=SC1091
source "$(dirname "${BASH_SOURCE[0]}")/ephe.inc"

TOKEN="$1"
[ "${TOKEN}" != "" ] || error "TOKEN is empty"

export NAMESPACE="$(oc project -q)"
CREDS="$( oc get secrets/env-${NAMESPACE}-keycloak -o jsonpath='{.data.defaultUsername}' | base64 -d )"
CREDS="${CREDS}:$( oc get secrets/env-${NAMESPACE}-keycloak -o jsonpath='{.data.defaultPassword}' | base64 -d )"
export CREDS

unset X_RH_IDENTITY
export X_RH_FAKE_IDENTITY="$( ./tools/bin/xrhidgen -org-id 12345 system -cn "6f324116-b3d2-11ed-8a37-482ae3863d30" -cert-type system | base64 -w0 )"
export X_RH_FAKE_IDENTITY="${X_RH_FAKE_IDENTITY:-$(identity_system)}"
export X_RH_IDM_REGISTRATION_TOKEN="${TOKEN}"
export X_RH_IDM_VERSION='{"ipa-hcc": "0.9", "ipa": "4.10.0-8.el9_1", "os-release-id": "rhel", "os-release-version-id": "9.1"}'
BASE_URL="https://$( oc get routes -l app=idmsvc-backend -o jsonpath='{.items[0].spec.host}' )/api/idmsvc/v1"
./scripts/curl.sh -i -X POST -d @<( cat "test/data/http/register-rhel-idm-domain.json" | sed -e 's/{{subscription_manager_id}}/6f324116-b3d2-11ed-8a37-482ae3863d30/g' ) "${BASE_URL}/domains"
X_RH_IDM_VERSION="$(idm_version)"
export X_RH_IDM_VERSION
"${REPOBASEDIR}/scripts/curl.sh" -i -X POST -d @<(sed -e 's/{{subscription_manager_id}}/6f324116-b3d2-11ed-8a37-482ae3863d30/g' < "${REPOBASEDIR}/test/data/http/register-rhel-idm-domain.json") "${BASE_URL}/domains"
12 changes: 5 additions & 7 deletions test/scripts/ephe-domains-token.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
#!/bin/bash
set -eo pipefail

export NAMESPACE="$(oc project -q)"
CREDS="$( oc get secrets/env-${NAMESPACE}-keycloak -o jsonpath='{.data.defaultUsername}' | base64 -d )"
CREDS="${CREDS}:$( oc get secrets/env-${NAMESPACE}-keycloak -o jsonpath='{.data.defaultPassword}' | base64 -d )"
export CREDS
# shellcheck disable=SC1091
source "$(dirname "${BASH_SOURCE[0]}")/ephe.inc"

unset X_RH_IDENTITY
export X_RH_FAKE_IDENTITY="$( ./tools/bin/xrhidgen -org-id 12345 user -is-active=true -is-org-admin=true -user-id test -username test | base64 -w0 )"
BASE_URL="https://$( oc get routes -l app=idmsvc-backend -o jsonpath='{.items[0].spec.host}' )/api/idmsvc/v1"
./scripts/curl.sh -i -X POST -d '{"domain_type": "rhel-idm"}' "${BASE_URL}/domains/token"
export X_RH_FAKE_IDENTITY="${X_RH_FAKE_IDENTITY:-$(identity_user)}"
"${REPOBASEDIR}/scripts/curl.sh" -i -X POST -d '{"domain_type": "rhel-idm"}' "${BASE_URL}/domains/token"
23 changes: 7 additions & 16 deletions test/scripts/ephe-domains-update.sh
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
#!/bin/bash
set -eo pipefail

function error {
local err=$?
printf "%s\n" "$1" >&2
exit $err
}

# make ephemeral-db-cli <<< "select domain_uuid from domains order by id desc limit 1;\\q"
# shellcheck disable=SC1091
source "$(dirname "${BASH_SOURCE[0]}")/ephe.inc"

UUID="$1"
[ "${UUID}" != "" ] || error "UUID is empty"

export NAMESPACE="$(oc project -q)"
CREDS="$( oc get secrets/env-${NAMESPACE}-keycloak -o jsonpath='{.data.defaultUsername}' | base64 -d )"
CREDS="${CREDS}:$( oc get secrets/env-${NAMESPACE}-keycloak -o jsonpath='{.data.defaultPassword}' | base64 -d )"
export CREDS

unset X_RH_IDENTITY
export X_RH_FAKE_IDENTITY="$( ./tools/bin/xrhidgen -org-id 12345 system -cn "6f324116-b3d2-11ed-8a37-482ae3863d30" -cert-type system | base64 -w0 )"
export X_RH_FAKE_IDENTITY="${X_RH_FAKE_IDENTITY:-$(identity_system)}"
unset X_RH_IDM_REGISTRATION_TOKEN
export X_RH_IDM_VERSION='{"ipa-hcc": "0.9", "ipa": "4.10.0-8.el9_1", "os-release-id": "rhel", "os-release-version-id": "9.1"}'
BASE_URL="https://$( oc get routes -l app=idmsvc-backend -o jsonpath='{.items[0].spec.host}' )/api/idmsvc/v1"
./scripts/curl.sh -i -X PUT -d @<( cat test/data/http/update-rhel-idm-domain.json | sed -e "s/{{createDomain.response.body.domain_id}}/${UUID}/g" -e 's/{{subscription_manager_id}}/6f324116-b3d2-11ed-8a37-482ae3863d30/g' ) "${BASE_URL}/domains/${UUID}"
X_RH_IDM_VERSION="$(idm_version)"
export X_RH_IDM_VERSION
"${REPOBASEDIR}/scripts/curl.sh" -i -X PUT -d @<(sed -e "s/{{createDomain.response.body.domain_id}}/${UUID}/g" -e 's/{{subscription_manager_id}}/6f324116-b3d2-11ed-8a37-482ae3863d30/g' < "${REPOBASEDIR}/test/data/http/update-rhel-idm-domain.json") "${BASE_URL}/domains/${UUID}"
23 changes: 8 additions & 15 deletions test/scripts/ephe-hostconf.sh
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
#!/bin/bash
set -eo pipefail

function error {
local err=$?
printf "%s\n" "$*" >&2
exit $err
}
# shellcheck disable=SC1091
source "$(dirname "${BASH_SOURCE[0]}")/ephe.inc"

INVENTORY_ID=$"$1"
FQDN="$2"
[ "${INVENTORY_ID}" != "" ] || error "INVENTORY_ID is empty"
FQDN="$2"
[ "${FQDN}" != "" ] || error "FQDN is empty"

export NAMESPACE="$(oc project -q)"
CREDS="$( oc get secrets/env-${NAMESPACE}-keycloak -o jsonpath='{.data.defaultUsername}' | base64 -d )"
CREDS="${CREDS}:$( oc get secrets/env-${NAMESPACE}-keycloak -o jsonpath='{.data.defaultPassword}' | base64 -d )"
export CREDS

unset X_RH_IDENTITY
export X_RH_FAKE_IDENTITY="$( ./tools/bin/xrhidgen -org-id 12345 system -cn "3f35fc7f-079c-4940-92ed-9fdc8694a0f3" -cert-type system | base64 -w0 )"
export X_RH_IDM_VERSION='{"ipa-hcc": "0.9", "ipa": "4.10.0-8.el9_1", "os-release-id": "rhel", "os-release-version-id": "9.1"}'
BASE_URL="https://$( oc get routes -l app=idmsvc-backend -o jsonpath='{.items[0].spec.host}' )/api/idmsvc/v1"
./scripts/curl.sh -i -X POST -d '{}' "${BASE_URL}/host-conf/${INVENTORY_ID}/${FQDN}"
export X_RH_FAKE_IDENTITY="${X_RH_FAKE_IDENTITY:-$(identity_system)}"
X_RH_IDM_VERSION="$(idm_version)"
export X_RH_IDM_VERSION
"${REPOBASEDIR}/scripts/curl.sh" -i -X POST -d '{}' "${BASE_URL}/host-conf/${INVENTORY_ID}/${FQDN}"
10 changes: 4 additions & 6 deletions test/scripts/ephe-openapi.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
#!/bin/bash
set -eo pipefail

export NAMESPACE="$(oc project -q)"
CREDS="$( oc get secrets/env-${NAMESPACE}-keycloak -o jsonpath='{.data.defaultUsername}' | base64 -d )"
CREDS="${CREDS}:$( oc get secrets/env-${NAMESPACE}-keycloak -o jsonpath='{.data.defaultPassword}' | base64 -d )"
export CREDS
# shellcheck disable=SC1091
source "$(dirname "${BASH_SOURCE[0]}")/ephe.inc"

unset X_RH_IDENTITY
unset X_RH_FAKE_IDENTITY
BASE_URL="https://$( oc get routes -l app=idmsvc-backend -o jsonpath='{.items[0].spec.host}' )/api/idmsvc/v1"
./scripts/curl.sh -i "${BASE_URL}/openapi.json"
"${REPOBASEDIR}/scripts/curl.sh" -i "${BASE_URL}/openapi.json"
21 changes: 21 additions & 0 deletions test/scripts/ephe.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#
# Include for common parts for ephemeral environment shared between all the scripts
#
# NOTE: Be aware that curl.sh wrapper set options based in the environment
# variables that has value when it is invoked, and set an environment
# variable could change the behave on how the request is formed.
#
# See: ./scripts/curl.sh
#
source "$(dirname "${BASH_SOURCE[0]}")/common.inc"

NAMESPACE="$(oc project -q)"
export NAMESPACE

username="$( oc get secrets/env-"${NAMESPACE}"-keycloak -o jsonpath='{.data.defaultUsername}' | base64 -d )"
password="$( oc get secrets/env-"${NAMESPACE}"-keycloak -o jsonpath='{.data.defaultPassword}' | base64 -d )"
CREDS="${username}:${password}"
export CREDS

# shellcheck disable=SC2034 # ignore unused variable
BASE_URL="https://$( oc get routes -l app=idmsvc-backend -o jsonpath='{.items[0].spec.host}' )/api/idmsvc/v1"
17 changes: 6 additions & 11 deletions test/scripts/local-domains-delete.sh
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
#!/bin/bash
set -eo pipefail

function error {
local err=$?
printf "%s\n" "$1" >&2
exit $err
}

# make db-cli <<< "select domain_uuid from domains order by id desc limit 1;\\q"
# shellcheck disable=SC1091
source "$(dirname "${BASH_SOURCE[0]}")/local.inc"

UUID="$1"
[ "${UUID}" != "" ] || error "UUID is empty"

export X_RH_IDENTITY="$( ./tools/bin/xrhidgen -org-id 12345 user -is-active=true -is-org-admin=true -user-id test -username test | base64 -w0 )"
export X_RH_IDENTITY="${X_RH_IDENTITY:-$(identity_user)}"
unset CREDS
export X_RH_IDM_REGISTRATION_TOKEN="$TOKEN"
export X_RH_IDM_VERSION="$( base64 -w0 <<< '{"ipa-hcc": "0.7", "ipa": "4.10.0-8.el9_1"}' )"
BASE_URL="http://localhost:8000/api/idmsvc/v1"
./scripts/curl.sh -i -X DELETE "${BASE_URL}/domains/${UUID}"
unset X_RH_IDM_VERSION
"${REPOBASEDIR}/scripts/curl.sh" -i -X DELETE "${BASE_URL}/domains/${UUID}"
10 changes: 6 additions & 4 deletions test/scripts/local-domains-list.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#!/bin/bash
set -eo pipefail

export X_RH_IDENTITY="$( ./tools/bin/xrhidgen -org-id 12345 user -is-active=true -is-org-admin=true -user-id test -username test | base64 -w0 )"
# shellcheck disable=SC1091
source "$(dirname "${BASH_SOURCE[0]}")/local.inc"

export X_RH_IDENTITY="${X_RH_IDENTITY:-$(identity_user)}"
unset X_RH_FAKE_IDENTITY
unset CREDS
unset X_RH_IDM_VERSION
BASE_URL="http://localhost:8000/api/idmsvc/v1"
./scripts/curl.sh -i "${BASE_URL}/domains"

"${REPOBASEDIR}/scripts/curl.sh" -i "${BASE_URL}/domains"
16 changes: 5 additions & 11 deletions test/scripts/local-domains-patch.sh
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
#!/bin/bash
set -eo pipefail

function error {
local err=$?
printf "%s\n" "$1" >&2
exit $err
}

# make db-cli <<< "select domain_uuid from domains order by id desc limit 1;\\q"
# make db-cli <<< "select token from ipas order by id desc limit 1;\\q"
# shellcheck disable=SC1091
source "$(dirname "${BASH_SOURCE[0]}")/local.inc"

UUID="$1"
[ "${UUID}" != "" ] || error "UUID is empty"

export X_RH_IDENTITY="$( ./bin/xrhidgen -org-id 12345 user -is-active=true -is-org-admin=true -user-id test -username test | base64 -w0 )"
export X_RH_IDENTITY="${X_RH_IDENTITY:-$(identity_user)}"
unset CREDS
unset X_RH_IDM_REGISTRATION_TOKEN
BASE_URL="http://localhost:8000/api/idmsvc/v1"
./scripts/curl.sh -i -X PATCH -d @<( cat "test/data/http/patch-rhel-idm-domain.json" | sed -e "s/{{createDomain.response.body.domain_id}}/${UUID}/g" ) "${BASE_URL}/domains/${UUID}"
"${REPOBASEDIR}/scripts/curl.sh" -i -X PATCH -d @<(sed -e "s/{{createDomain.response.body.domain_id}}/${UUID}/g" < "${REPOBASEDIR}/test/data/http/patch-rhel-idm-domain.json") "${BASE_URL}/domains/${UUID}"
Loading

0 comments on commit cb547b2

Please sign in to comment.