From 131b964d88c025d36bb541da88226f56a70e203e Mon Sep 17 00:00:00 2001 From: Iain Sproat <68657+iainsproat@users.noreply.github.com> Date: Tue, 27 May 2025 12:26:30 +0100 Subject: [PATCH 01/10] chore(pre-commit): fix json schema generation (#4825) --- .pre-commit-config.yaml | 16 ++++++++-------- utils/helm/update-schema-json.sh | 9 ++++++++- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 96c42f5c0..cfa71703e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -36,14 +36,14 @@ repos: args: - --ignore=E501 # ignoring error about lines that are too long - # - repo: local - # hooks: - # - id: helm-documentation - # name: Helm Json Schema - # language: system - # files: utils\/helm\/speckle\-server\/values\.yaml - # entry: utils/helm/update-schema-json.sh - # description: If this fails it is because the values.yaml file was updated. Or has missing or incorrect documentation. + - repo: local + hooks: + - id: helm-documentation + name: Helm Json Schema + language: system + files: utils\/helm\/speckle\-server\/values\.yaml + entry: utils/helm/update-schema-json.sh + description: If this fails it is because the values.yaml file was updated. Or has missing or incorrect documentation. # helmlint should occur after the json schema is updated - repo: https://github.com/gruntwork-io/pre-commit diff --git a/utils/helm/update-schema-json.sh b/utils/helm/update-schema-json.sh index d4078a34e..6d1d5813f 100755 --- a/utils/helm/update-schema-json.sh +++ b/utils/helm/update-schema-json.sh @@ -21,7 +21,14 @@ JSON_SCHEMA_PATH="${GIT_ROOT}/utils/helm/speckle-server/values.schema.json" if [ ! -d "${README_GENERATOR_DIR}" ]; then echo "๐Ÿ”ญ Could not find readme-generator-for-helm in a sibling directory to speckle-server" echo "๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง Proceeding with cloning readme-generator-for-helm to a sibling directory, readme-generator-for-helm" - git clone git@github.com:bitnami-labs/readme-generator-for-helm.git "${README_GENERATOR_DIR}" + SSH_OUTPUT="$(ssh -T git@github.com 2>&1 || true)" + if echo "${SSH_OUTPUT}" | grep -q 'successfully authenticated'; then + echo "๐Ÿ”‘ SSH authentication successful, cloning using SSH" + git clone git@github.com:bitnami-labs/readme-generator-for-helm.git "${README_GENERATOR_DIR}" + else + echo "๐Ÿ”‘ SSH authentication failed, cloning using HTTPS" + git clone https://github.com/bitnami-labs/readme-generator-for-helm "${README_GENERATOR_DIR}" + fi fi pushd "${README_GENERATOR_DIR}" From aaff6cccf62db00a0b26c000c476d4485c662a26 Mon Sep 17 00:00:00 2001 From: andrewwallacespeckle Date: Tue, 27 May 2025 13:57:11 +0200 Subject: [PATCH 02/10] fix(fe): use loadedVersion for limits dialog and improve resource string handling --- .../frontend-2/components/viewer/PreSetupWrapper.vue | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/frontend-2/components/viewer/PreSetupWrapper.vue b/packages/frontend-2/components/viewer/PreSetupWrapper.vue index 9620a4c58..4866f9948 100644 --- a/packages/frontend-2/components/viewer/PreSetupWrapper.vue +++ b/packages/frontend-2/components/viewer/PreSetupWrapper.vue @@ -126,6 +126,7 @@ import { useFilterUtilities } from '~/lib/viewer/composables/ui' import { projectsRoute, workspaceRoute } from '~~/lib/common/helpers/route' import { useMixpanel } from '~/lib/core/composables/mp' import { writableAsyncComputed } from '~/lib/common/composables/async' +import { resourceBuilder } from '@speckle/shared/viewer/route' graphql(` fragment ModelPageProject on Project { @@ -200,11 +201,14 @@ const hasMissingReferencedObject = computed(() => { const resourceIds = resourceIdString.value.split(',') const result = modelsAndVersionIds.value.some((item) => { - const version = item.model?.versions?.items?.find((v) => v.id === item.versionId) + const version = item.model?.loadedVersion?.items?.find( + (v) => v.id === item.versionId + ) - if (version && version.referencedObject === null) { - // Check if this model+version is in the URL (latest version always available) - const modelVersionString = `${item.model.id}@${item.versionId}`.toLowerCase() + if (!version || version.referencedObject === null) { + const modelVersionString = resourceBuilder() + .addModel(item.model.id, item.versionId) + .toString() const isInUrl = resourceIds.some((r) => r.toLowerCase() === modelVersionString) return isInUrl From 634fdc0baab706fb3905d1f2de324af30a26bfd8 Mon Sep 17 00:00:00 2001 From: andrewwallacespeckle Date: Tue, 27 May 2025 14:01:31 +0200 Subject: [PATCH 03/10] Use parseUrlParameters --- .../components/viewer/PreSetupWrapper.vue | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/frontend-2/components/viewer/PreSetupWrapper.vue b/packages/frontend-2/components/viewer/PreSetupWrapper.vue index 4866f9948..d1e930ce2 100644 --- a/packages/frontend-2/components/viewer/PreSetupWrapper.vue +++ b/packages/frontend-2/components/viewer/PreSetupWrapper.vue @@ -126,7 +126,7 @@ import { useFilterUtilities } from '~/lib/viewer/composables/ui' import { projectsRoute, workspaceRoute } from '~~/lib/common/helpers/route' import { useMixpanel } from '~/lib/core/composables/mp' import { writableAsyncComputed } from '~/lib/common/composables/async' -import { resourceBuilder } from '@speckle/shared/viewer/route' +import { parseUrlParameters, resourceBuilder } from '@speckle/shared/viewer/route' graphql(` fragment ModelPageProject on Project { @@ -198,7 +198,7 @@ const limitsDialogType = ref<'version' | 'comment' | 'federated'>('version') // Check for missing referencedObject in url referenced versions (out of plan limits) const hasMissingReferencedObject = computed(() => { - const resourceIds = resourceIdString.value.split(',') + const resources = parseUrlParameters(resourceIdString.value) const result = modelsAndVersionIds.value.some((item) => { const version = item.model?.loadedVersion?.items?.find( @@ -209,7 +209,9 @@ const hasMissingReferencedObject = computed(() => { const modelVersionString = resourceBuilder() .addModel(item.model.id, item.versionId) .toString() - const isInUrl = resourceIds.some((r) => r.toLowerCase() === modelVersionString) + const isInUrl = resources.some( + (r) => r.toString().toLowerCase() === modelVersionString + ) return isInUrl } @@ -318,4 +320,12 @@ watch( }, { immediate: true } ) + +watch( + [hasMissingReferencedObject, modelsAndVersionIds], + ([hasMissing]) => { + showLimitsDialog.value = hasMissing + }, + { immediate: true } +) From b88b8cb11a921dc5b7b14e089dcf46a00b33008d Mon Sep 17 00:00:00 2001 From: andrewwallacespeckle Date: Tue, 27 May 2025 14:59:30 +0200 Subject: [PATCH 04/10] Merge watches --- .../components/viewer/PreSetupWrapper.vue | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/frontend-2/components/viewer/PreSetupWrapper.vue b/packages/frontend-2/components/viewer/PreSetupWrapper.vue index d1e930ce2..e32ffafcc 100644 --- a/packages/frontend-2/components/viewer/PreSetupWrapper.vue +++ b/packages/frontend-2/components/viewer/PreSetupWrapper.vue @@ -294,7 +294,13 @@ onMounted(() => { // Watch for plan limit conditions and show dialog if needed watch( - [hasMissingReferencedObject, hasMissingThread, resourceItems, project], + [ + hasMissingReferencedObject, + hasMissingThread, + resourceItems, + project, + modelsAndVersionIds + ], ([missingObject, missingThread]) => { if (missingObject) { if (isFederated.value) { @@ -316,16 +322,10 @@ watch( if (missingThread && isFederated.value && hasMissingReferencedObject.value) { limitsDialogType.value = 'comment' showLimitsDialog.value = true + } else { + showLimitsDialog.value = false } }, { immediate: true } ) - -watch( - [hasMissingReferencedObject, modelsAndVersionIds], - ([hasMissing]) => { - showLimitsDialog.value = hasMissing - }, - { immediate: true } -) From 41cbeeb9ab039438f42d820dafbfe72fd8cc3872 Mon Sep 17 00:00:00 2001 From: andrewwallacespeckle Date: Tue, 27 May 2025 15:37:30 +0200 Subject: [PATCH 05/10] Changes from fabs --- .../components/viewer/PreSetupWrapper.vue | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/packages/frontend-2/components/viewer/PreSetupWrapper.vue b/packages/frontend-2/components/viewer/PreSetupWrapper.vue index e32ffafcc..74217a9b6 100644 --- a/packages/frontend-2/components/viewer/PreSetupWrapper.vue +++ b/packages/frontend-2/components/viewer/PreSetupWrapper.vue @@ -294,13 +294,7 @@ onMounted(() => { // Watch for plan limit conditions and show dialog if needed watch( - [ - hasMissingReferencedObject, - hasMissingThread, - resourceItems, - project, - modelsAndVersionIds - ], + [hasMissingReferencedObject, hasMissingThread, resourceItems, project], ([missingObject, missingThread]) => { if (missingObject) { if (isFederated.value) { @@ -310,16 +304,7 @@ watch( } showLimitsDialog.value = true return - } - - // If no workspace and no missing objects, don't show dialog - if (!project.value?.workspace) { - showLimitsDialog.value = false - return - } - - // Only show comment dialog if it's a federated view AND we have a missing referenced object - if (missingThread && isFederated.value && hasMissingReferencedObject.value) { + } else if (missingThread && isFederated.value && hasMissingReferencedObject.value) { limitsDialogType.value = 'comment' showLimitsDialog.value = true } else { From 264312390559e21f5aa3ac4286256d0b77279dc1 Mon Sep 17 00:00:00 2001 From: Iain Sproat <68657+iainsproat@users.noreply.github.com> Date: Tue, 27 May 2025 15:34:02 +0100 Subject: [PATCH 06/10] ci(helm-documentation): removes it from speckle-server (#4826) - now part of specklesystems/helm workflows --- .circleci/config.yml | 20 -------- .circleci/update_helm_documentation.sh | 71 -------------------------- 2 files changed, 91 deletions(-) delete mode 100755 .circleci/update_helm_documentation.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index ebcf86415..57fdc36fd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -372,11 +372,6 @@ workflows: - get-version - publish-approval - - update-helm-documentation: - filters: *filters-publish - requires: - - publish-helm-chart - - publish-npm: filters: tags: @@ -1110,21 +1105,6 @@ jobs: name: Publish Helm Chart command: ./.circleci/publish_helm_chart.sh - update-helm-documentation: - <<: *docker-node-image - working_directory: *work-dir - steps: - - checkout - - attach_workspace: - at: /tmp/ci/workspace - - run: cat workspace/env-vars >> $BASH_ENV - - add_ssh_keys: - fingerprints: - - '4d:68:70:66:49:97:ba:8b:8c:55:96:df:3d:be:6e:05' - - run: - name: Update Helm Documentation - command: ./.circleci/update_helm_documentation.sh - publish-viewer-sandbox-cloudflare-pages: <<: *docker-node-image working_directory: *work-dir diff --git a/.circleci/update_helm_documentation.sh b/.circleci/update_helm_documentation.sh deleted file mode 100755 index dcd971ffd..000000000 --- a/.circleci/update_helm_documentation.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail -if ! command -v node &> /dev/null -then - echo "๐Ÿ›‘ node could not be found. Please install node (and ensure it is in your PATH) before trying again." - exit 1 -fi - -if ! command -v git &> /dev/null -then - echo "๐Ÿ›‘ git could not be found. Please install git (and ensure it is in your PATH) before trying again." - exit 1 -fi - -GIT_ROOT="$(git rev-parse --show-toplevel)" - -README_GENERATOR_DIR="${GIT_ROOT}/../readme-generator-for-helm" -HELM_DIR="${GIT_ROOT}/../speckle-helm" -HELM_GIT_TARGET_BRANCH="gh-pages" - -if [ ! -d "${README_GENERATOR_DIR}" ]; then - echo "๐Ÿ”ญ Could not find 'readme-generator-for-helm' in a sibling directory" - echo "๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง Proceeding with cloning readme-generator-for-helm to a sibling directory, 'readme-generator-for-helm'" - git clone git@github.com:bitnami-labs/readme-generator-for-helm.git "${README_GENERATOR_DIR}" -fi - -if [ -n "${CI}" ]; then - git config --global user.email "devops+circleci@speckle.systems" - git config --global user.name "CI" -fi - -pushd "${README_GENERATOR_DIR}" - echo "โœจ Updating to the latest version of readme-generator-for-helm" - git switch main - git pull origin main - npm install -popd - -if [ ! -d "${HELM_DIR}" ]; then - echo "๐Ÿ”ญ Could not find Speckle Helm in a sibling directory (named 'speckle-helm')" - echo "๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง Proceeding with cloning Speckle's helm repository to a sibling directory, 'speckle-helm'" - git clone git@github.com:specklesystems/helm.git "${HELM_DIR}" -fi - -pushd "${HELM_DIR}" - echo "โœจ Updating to the latest version of Speckle helm" - git switch main - git pull origin main - echo "๐Ÿฝ Preparing gh-pages branch for updates" - git switch "${HELM_GIT_TARGET_BRANCH}" - git pull origin "${HELM_GIT_TARGET_BRANCH}" -popd - -pushd "${GIT_ROOT}" - echo "๐Ÿ— Generating the documentation" - node "${README_GENERATOR_DIR}/bin/index.js" \ - --config "${GIT_ROOT}/utils/helm/.helm-readme-configuration.json" \ - --values "${GIT_ROOT}/utils/helm/speckle-server/values.yaml" \ - --readme "${HELM_DIR}/README.md" -popd - -pushd "${HELM_DIR}" - echo "๐ŸŒณ Preparing commit to branch '${HELM_GIT_TARGET_BRANCH}' for Helm README..." - if [[ $(git status --porcelain) ]]; then - git add README.md - git commit -m "Updating README with revised parameters from values.yaml of Helm Chart." - git push --set-upstream origin "${HELM_GIT_TARGET_BRANCH}" - fi -popd - -echo "โœ… All done ๐ŸŽ‰" From 15274d13cfe21761a0ca719cc107133698038594 Mon Sep 17 00:00:00 2001 From: Iain Sproat <68657+iainsproat@users.noreply.github.com> Date: Tue, 27 May 2025 17:47:28 +0100 Subject: [PATCH 07/10] chore(/auth/token): make thrown error more specific about message (#4830) --- packages/server/modules/auth/rest/index.ts | 30 ++++++++++++++-------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/packages/server/modules/auth/rest/index.ts b/packages/server/modules/auth/rest/index.ts index a46cf4033..c183f95b2 100644 --- a/packages/server/modules/auth/rest/index.ts +++ b/packages/server/modules/auth/rest/index.ts @@ -113,6 +113,15 @@ export default function (app: Express) { app.options('/auth/token', corsMiddlewareFactory()) app.post('/auth/token', corsMiddlewareFactory(), async (req, res) => { try { + if (!req.body.appId) + throw new BadRequestError( + `Invalid request, insufficient information provided. App Id is required.` + ) + if (!req.body.appSecret) + throw new BadRequestError( + `Invalid request, insufficient information provided. App Secret is required.` + ) + const createRefreshToken = createRefreshTokenFactory({ db }) const getApp = getAppFactory({ db }) const createAppToken = createAppTokenFactory({ @@ -143,9 +152,11 @@ export default function (app: Express) { }) // Token refresh - if (req.body.refreshToken) { - if (!req.body.appId || !req.body.appSecret) - throw new BadRequestError('Invalid request - App Id and Secret are required.') + if ('refreshToken' in req.body) { + if (!req.body.refreshToken) + throw new BadRequestError( + 'Invalid request, insufficient information provided. A valid refresh token is required.' + ) const authResponse = await withOperationLogging( async () => @@ -164,14 +175,13 @@ export default function (app: Express) { } // Access-code - token exchange - if ( - !req.body.appId || - !req.body.appSecret || - !req.body.accessCode || - !req.body.challenge - ) + if (!req.body.accessCode) throw new BadRequestError( - `Invalid request, insufficient information provided in the request. App Id, Secret, Access Code, and Challenge are required.` + `Invalid request, insufficient information provided. Access Code is required.` + ) + if (!req.body.challenge) + throw new BadRequestError( + `Invalid request, insufficient information provided. Challenge is required.` ) const authResponse = await withOperationLogging( From 1349ea714e3f09971ca8183e804e7d5b310043bf Mon Sep 17 00:00:00 2001 From: Iain Sproat <68657+iainsproat@users.noreply.github.com> Date: Wed, 28 May 2025 08:43:31 +0100 Subject: [PATCH 08/10] fix(server): ensure object IDs are like MD5 hashes; 32 character hexadecimal (#4392) --- packages/server/modules/core/services/objects/management.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/server/modules/core/services/objects/management.ts b/packages/server/modules/core/services/objects/management.ts index c8c3a0039..fe665ba02 100644 --- a/packages/server/modules/core/services/objects/management.ts +++ b/packages/server/modules/core/services/objects/management.ts @@ -34,6 +34,12 @@ const prepInsertionObject = ( obj.id = obj.id || crypto.createHash('md5').update(JSON.stringify(obj)).digest('hex') // generate a hash if none is present + if (obj.id.length !== 32) { + throw new ObjectHandlingError( + `Invalid object ID. Object ID: ${obj.id}. Object ID's must be hashes represented by a string of 32 characters.` + ) + } + const stringifiedObj = JSON.stringify(obj) const objectByteSize = estimateStringMegabyteSize(stringifiedObj) if (objectByteSize > MAX_OBJECT_SIZE_MB) { From b9a27e708614dd88e0c8dee5cfeaab007d142c47 Mon Sep 17 00:00:00 2001 From: Benjamin Ottensten Date: Wed, 28 May 2025 09:55:50 +0200 Subject: [PATCH 09/10] Fix: Improve copy in intro call step (#4831) --- packages/frontend-2/pages/book-a-demo.vue | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/frontend-2/pages/book-a-demo.vue b/packages/frontend-2/pages/book-a-demo.vue index 5280b8964..92b81da2d 100644 --- a/packages/frontend-2/pages/book-a-demo.vue +++ b/packages/frontend-2/pages/book-a-demo.vue @@ -20,11 +20,13 @@

- +