feat(cli): add workflow-configs pull and push#282
Conversation
@transcend-io/airgap.js-types
@transcend-io/cli
@transcend-io/internationalization
@transcend-io/privacy-types
@transcend-io/sdk
@transcend-io/type-utils
@transcend-io/utils
@transcend-io/mcp
@transcend-io/mcp-server-admin
@transcend-io/mcp-server-assessment
@transcend-io/mcp-server-base
@transcend-io/mcp-server-consent
@transcend-io/mcp-server-discovery
@transcend-io/mcp-server-docs
@transcend-io/mcp-server-dsr
@transcend-io/mcp-server-inventory
@transcend-io/mcp-server-preferences
@transcend-io/mcp-server-workflows
commit: |
Add workflow-configs top-level field for DSR workflow settings with SDK fetch/sync, tr-pull resource, and update-only tr-push sync. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
13ad1a8 to
94aa588
Compare
Address PR review feedback: - Configs no longer carry opaque IDs; they sync by their unique human-readable title (update-only lookup, errors on missing/ambiguous). - Support more fields: collect-data-subject-regions, per-region expiry-time, and attribute-keys (by name), plus a CollectDataSubjectRegions enum in privacy-types.
Use title-based sync without IDs in examples, proper enum codecs, typed WorkflowConfigNode from GraphQL, indexBy for lookups, and README nav fix.
Include @transcend-io/type-utils in the PR changeset and run oxfmt on README and syncWorkflowConfigs files that failed format:check:root.
Use pull/push-specific workflow nav labels in docgen, revert indexBy in favor of lodash keyBy, and drop the type-utils changeset entry.
Use internal-name + action-type as required YAML fields (matching create semantics), pull all workflow config types, and simplify docgen nav to a single Workflows -> DSR Workflows link.
Inline workflow configs docgen link and remove type casts in sync fetch logic.
Resolve conflicts by keeping both workflow-configs and preference-options pull/push support. Co-authored-by: Cursor <cursoragent@cursor.com>
- Pull scope: ManageWorkflows (the workflows query is not granted by ViewDataSubjectRequestSettings); push scopes now include ViewDataSubjectRequestSettings + ViewGlobalAttributes for lookups - Filter pull to DSR workflows and reject non-DSR configs on push - Validate expiry-time client-side (default entry required, values > 0) - Replace invalid EU region code in examples with GB/DE/FR - Add syncWorkflowConfigs unit tests and regenerate README scope tables
Add ViewWorkflows as a view-only scope for workflow-configs pull, with ManageWorkflows inheriting ViewWorkflows plus the data-subject and attribute view scopes needed for push sync. Simplify CLI scope mappings, pull all workflow config types, remove syncWorkflowConfigs unit tests per review, and regenerate README scope tables. Co-authored-by: Cursor <cursoragent@cursor.com>
The ViewWorkflows scope was added to privacy-types but the generated CLI YAML schema was not regenerated, causing the "Verify generated CLI files are up to date" CI check to fail.
| region-list: | ||
| - US | ||
| - CA | ||
| expiry-time: | ||
| # A `region: default` entry is required whenever expiry-time is set | ||
| - region: default | ||
| value: 45 | ||
| - region: CA |
There was a problem hiding this comment.
Do we want to include a subdivision code example here for completeness? Could make this US-CA.
| region-list: | |
| - US | |
| - CA | |
| expiry-time: | |
| # A `region: default` entry is required whenever expiry-time is set | |
| - region: default | |
| value: 45 | |
| - region: CA | |
| region-list: | |
| - US | |
| - US-CA | |
| expiry-time: | |
| # A `region: default` entry is required whenever expiry-time is set | |
| - region: default | |
| value: 45 | |
| - region: US-CA |
| visibility: config.workflowConfigVisibility, | ||
| type: config.workflowConfigType, |
There was a problem hiding this comment.
why do we change so many of these names and structures? It seems like it would be easier for the user to follow if they were as close to the GQL schema as possible. It also seems easier for developers to follow and keep these in sync as we add more properties.
| }, | ||
| [TranscendPullResource.WorkflowConfigs]: { | ||
| description: | ||
| 'Workflow config settings (update-only — workflow configs are created in the Admin Dashboard).', |
There was a problem hiding this comment.
Where does this comment get shown? "(update-only — workflow configs are created in the Admin Dashboard)" feels only relevant to the "push" action, so I'm wondering if there's a different place we could put this note where it is more targeted. But that's just a nit.
| if (duplicates.length > 0) { | ||
| throw new Error( | ||
| `Found "${matches.length}" workflow configs with internal name: "${internalName}". ` + | ||
| 'Internal names must be unique to sync workflow configs.', | ||
| ); | ||
| } |
There was a problem hiding this comment.
I wonder if we should just make these unique in the db
There was a problem hiding this comment.
ya i was thinking same thing....
There was a problem hiding this comment.
cool if i make that change?
Ref WAL-10250
Summary
Adds top-level
workflow-configsfor DSR workflow settings.Update-only — workflow configs must be created in the Admin Dashboard first. Sync never creates configs; pushing an unknown internal name fails with a clear error.
YAML entries are matched to existing configs by
internal-name(required, must be unique across the org; set it in the Admin Dashboard first). Workflows without an internal name are skipped on pull with a warning.action-typeis required. Changing a workflow's action type creates a new workflow version server-side — treat it as a deliberate, versioned change, not a cosmetic edit.Pull is filtered to
workflowConfigType: DSR; preference-management workflows are excluded on pull and rejected on push (they have purpose-based semantics and must be managed in the Admin Dashboard).Client-side validation:
expiry-time, when set, must include aregion: defaultentry and all values must be > 0 (mirrors the backendRegionExpiryMapvalidation, but fails before any mutation is sent).SDK:
fetchAllWorkflowConfigs,syncWorkflowConfigs(+ unit tests for the negative paths)CLI:
WorkflowConfigInputcodec, pull resource, push syncExample:
packages/cli/examples/workflow-configs.ymlRecent updates
View Workflows(viewWorkflows) scope for the DSR Automation product so pull no longer requires a manage/write scope. It depends onView Data Subject Request Settings+View Global Attributes(needed to resolve action / data-subject / attribute-key IDs to names).Manage Workflowsnow depends onView Workflows+ those two view scopes, so push only needsManage Workflows.viewWorkflowsscope enum value.Required scopes
workflowsGraphQL query is granted by the read-onlyViewWorkflowsscope, which inheritsViewDataSubjectRequestSettings+ViewGlobalAttributesto resolve action / data-subject / attribute-key IDs to namesupdateWorkflowConfig+ theworkflowsquery needManageWorkflows, which inheritsViewWorkflows,ViewDataSubjectRequestSettings, andViewGlobalAttributes(used to resolve names to IDs)Example YAML
Region codes must be real ISO country / subdivision codes (
GB,DE,US-CA, ...).EUis not a valid code and is rejected by both the CLI codec and the backend.Test plan
Prod test against the Rideshare demo org (
rideshare-dating-demoon https://app.transcend.io).Setup
View Workflows+ the required view scopes via dependencies).export TRANSCEND_URL=https://api.transcend.ioandexport TRANSCEND_API_KEY=...Test 1 — pull
Verify:
PREFERENCE_MANAGEMENT).internal-nameandaction-type.Test 2 — scope negative test
Repeat the pull with an API key that has only View Data Subject Request Settings (i.e. missing View Workflows). Expect an access-denied error naming the View Workflows scope (confirms the scope table is honest).
Test 3 — push a safe, reversible edit
subtitle(append " (cli test)").visibilityoraction-typeon this org.Test 4 — negative tests
internal-name: does-not-exist-cli-test→ expect a clear "must be created in the Admin Dashboard" error and non-zero exit.region-list: [EU]→ expect a codec decode error before any network call.expiry-timelist without adefaultregion entry → expect the new client-side validation error.Cleanup
Delete the test API keys and confirm the org's workflows match their pre-test state via a final pull + diff.
Made with Cursor