From 9aeeaf76443445653c955f415deba0590cb14aa8 Mon Sep 17 00:00:00 2001 From: Luisina Santos Date: Tue, 21 Jul 2026 13:48:54 -0300 Subject: [PATCH 1/2] fix(account-status-lifecycle-test): read resource-level status, not just deprecated trait The account-status-lifecycle-test read user status only from the deprecated UserTrait annotation (`UserTrait_Status_Status`). In baton-sdk versions that moved status to a resource-level attribute (`Status_ResourceStatus`), a connector that sets only the resource-level status leaves the trait status unset, and the SDK defaults an unset trait status to STATUS_ENABLED. As a result the test always read STATUS_ENABLED and disable verifications failed even when the account was correctly disabled. get_user_status now reads both locations, prefers the resource-level value (normalized from RESOURCE_STATUS_* to the trait form STATUS_*), and falls back to the trait value only when no resource-level status is present. This keeps the action compatible with connectors built against any baton-sdk version. Co-Authored-By: Claude Opus 4.8 --- .../account-status-lifecycle-test/README.md | 7 ++- .../account-status-lifecycle-test.sh | 43 ++++++++++++++----- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/actions/account-status-lifecycle-test/README.md b/actions/account-status-lifecycle-test/README.md index 87325d5..885ddb6 100644 --- a/actions/account-status-lifecycle-test/README.md +++ b/actions/account-status-lifecycle-test/README.md @@ -117,8 +117,11 @@ The action performs account status tests based on the selected `test-flow`: ## Status Detection The action checks for account status using the following logic: -- Extracts status from the UserTrait annotation -- Checks if status equals `STATUS_ENABLED` (the only enabled status in baton-sdk) +- Reads status from both places it can live, depending on the connector's baton-sdk version: + - Resource-level `resource.status.status` (`Status_ResourceStatus` enum, e.g. `RESOURCE_STATUS_ENABLED`) — used by newer SDKs. + - The deprecated UserTrait annotation's `status.status` (`UserTrait_Status_Status` enum, e.g. `STATUS_ENABLED`). +- Prefers the resource-level value (normalized to the trait form) and falls back to the trait value. Newer SDKs default the deprecated trait status to `STATUS_ENABLED` when it isn't set explicitly, so the trait value alone is unreliable and is only used when no resource-level status is present. +- Checks if the resulting status equals `STATUS_ENABLED` (the only enabled status in baton-sdk) - Any other status value is considered disabled: - `STATUS_DISABLED` - Account is disabled - `STATUS_DELETED` - Account is deleted diff --git a/actions/account-status-lifecycle-test/account-status-lifecycle-test.sh b/actions/account-status-lifecycle-test/account-status-lifecycle-test.sh index d1d1c58..7486ce8 100755 --- a/actions/account-status-lifecycle-test/account-status-lifecycle-test.sh +++ b/actions/account-status-lifecycle-test/account-status-lifecycle-test.sh @@ -41,20 +41,41 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "${SCRIPT_DIR}/../_helpers/sleep.sh" # Function to get user status (enabled/disabled) +# +# Status can live in one of two places depending on the baton-sdk version the +# connector was built with: +# * Resource-level: .resource.status.status, using the Status_ResourceStatus +# enum (e.g. "RESOURCE_STATUS_ENABLED"). This is where newer SDKs put it. +# * Deprecated trait-level: the UserTrait annotation's .status.status, using +# the UserTrait_Status_Status enum (e.g. "STATUS_ENABLED"). +# +# We read both and prefer the resource-level value, normalizing it to the +# trait-form ("RESOURCE_STATUS_ENABLED" -> "STATUS_ENABLED") so the rest of the +# script keeps comparing against STATUS_ENABLED/STATUS_DISABLED. Newer SDKs +# default the deprecated trait status to STATUS_ENABLED when it isn't set +# explicitly, so the trait value alone is unreliable and is only used as a +# fallback when no resource-level status is present. get_user_status() { local user_id="$1" - local status=$(baton resources -t "user" --output-format=json \ + baton resources -t "user" --output-format=json \ | jq -r --arg user_id "$user_id" \ - '(.resources // [])[] | - select(.resource.id.resource == $user_id) | - (.resource.annotations[]? | select(."@type" == "type.googleapis.com/c1.connector.v2.UserTrait")) as $trait | - if $trait != null and $trait.status != null then - $trait.status - else - "unknown" - end') - # Extract just the status value if it's JSON, otherwise return as-is - echo "$status" | jq -r '.status // empty' 2>/dev/null || echo "$status" + '(.resources // [])[] + | select(.resource.id.resource == $user_id) + | .resource as $r + # Resource-level status (newer baton-sdk): Status_ResourceStatus enum. + | ($r.status.status // null) as $resStatus + # Deprecated trait-level status: UserTrait_Status_Status enum. + | (( + $r.annotations[]? + | select(."@type" == "type.googleapis.com/c1.connector.v2.UserTrait") + | .status.status + ) // null) as $traitStatus + # Normalize "RESOURCE_STATUS_*" to the trait-form "STATUS_*". + | (if $resStatus == null then null else ($resStatus | sub("^RESOURCE_"; "")) end) as $resNorm + | if ($resNorm != null and $resNorm != "STATUS_UNSPECIFIED") then $resNorm + elif ($traitStatus != null and $traitStatus != "STATUS_UNSPECIFIED") then $traitStatus + else "unknown" + end' } # Function to check if user is enabled From c169ddee541d31ca4ec385f56e0d1407fcfe77b0 Mon Sep 17 00:00:00 2001 From: Luisina Santos Date: Tue, 21 Jul 2026 15:32:37 -0300 Subject: [PATCH 2/2] docs: name the baton-sdk version (v0.19.0) that moved status to the resource Addresses review feedback: explicitly call out that baton-sdk v0.19.0 (ConductorOne/baton-sdk#996) is where status moved from the deprecated UserTrait field to the resource-level attribute. Co-Authored-By: Claude Opus 4.8 --- actions/account-status-lifecycle-test/README.md | 6 +++--- .../account-status-lifecycle-test.sh | 10 ++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/actions/account-status-lifecycle-test/README.md b/actions/account-status-lifecycle-test/README.md index 885ddb6..bb05518 100644 --- a/actions/account-status-lifecycle-test/README.md +++ b/actions/account-status-lifecycle-test/README.md @@ -118,9 +118,9 @@ The action performs account status tests based on the selected `test-flow`: The action checks for account status using the following logic: - Reads status from both places it can live, depending on the connector's baton-sdk version: - - Resource-level `resource.status.status` (`Status_ResourceStatus` enum, e.g. `RESOURCE_STATUS_ENABLED`) — used by newer SDKs. - - The deprecated UserTrait annotation's `status.status` (`UserTrait_Status_Status` enum, e.g. `STATUS_ENABLED`). -- Prefers the resource-level value (normalized to the trait form) and falls back to the trait value. Newer SDKs default the deprecated trait status to `STATUS_ENABLED` when it isn't set explicitly, so the trait value alone is unreliable and is only used when no resource-level status is present. + - Resource-level `resource.status.status` (`Status_ResourceStatus` enum, e.g. `RESOURCE_STATUS_ENABLED`) — used by connectors built against baton-sdk **v0.19.0+**, which moved status from the trait to the resource ([ConductorOne/baton-sdk#996](https://github.com/ConductorOne/baton-sdk/pull/996)). + - The deprecated UserTrait annotation's `status.status` (`UserTrait_Status_Status` enum, e.g. `STATUS_ENABLED`) — used by connectors built against baton-sdk **< v0.19.0**. +- Prefers the resource-level value (normalized to the trait form) and falls back to the trait value. On v0.19.0+ the deprecated trait status defaults to `STATUS_ENABLED` when it isn't set explicitly, so the trait value alone is unreliable and is only used when no resource-level status is present. - Checks if the resulting status equals `STATUS_ENABLED` (the only enabled status in baton-sdk) - Any other status value is considered disabled: - `STATUS_DISABLED` - Account is disabled diff --git a/actions/account-status-lifecycle-test/account-status-lifecycle-test.sh b/actions/account-status-lifecycle-test/account-status-lifecycle-test.sh index 7486ce8..928e0ab 100755 --- a/actions/account-status-lifecycle-test/account-status-lifecycle-test.sh +++ b/actions/account-status-lifecycle-test/account-status-lifecycle-test.sh @@ -45,14 +45,16 @@ source "${SCRIPT_DIR}/../_helpers/sleep.sh" # Status can live in one of two places depending on the baton-sdk version the # connector was built with: # * Resource-level: .resource.status.status, using the Status_ResourceStatus -# enum (e.g. "RESOURCE_STATUS_ENABLED"). This is where newer SDKs put it. +# enum (e.g. "RESOURCE_STATUS_ENABLED"). baton-sdk v0.19.0 moved status here +# from the trait (ConductorOne/baton-sdk#996) and deprecated the trait field. # * Deprecated trait-level: the UserTrait annotation's .status.status, using -# the UserTrait_Status_Status enum (e.g. "STATUS_ENABLED"). +# the UserTrait_Status_Status enum (e.g. "STATUS_ENABLED"). Used by +# connectors built against baton-sdk < v0.19.0. # # We read both and prefer the resource-level value, normalizing it to the # trait-form ("RESOURCE_STATUS_ENABLED" -> "STATUS_ENABLED") so the rest of the -# script keeps comparing against STATUS_ENABLED/STATUS_DISABLED. Newer SDKs -# default the deprecated trait status to STATUS_ENABLED when it isn't set +# script keeps comparing against STATUS_ENABLED/STATUS_DISABLED. On v0.19.0+ the +# deprecated trait status defaults to STATUS_ENABLED when it isn't set # explicitly, so the trait value alone is unreliable and is only used as a # fallback when no resource-level status is present. get_user_status() {