Skip to content

Commit b476846

Browse files
Eliminate duplicate label code and fix permission requirements
Consolidate label resolution to single location after both regular launch and resume workflow paths have set up body.launch. Both code paths ultimately populate body.launch, so labels can be applied once instead of duplicating the logic in two places. Fix permission requirements in error messages and documentation: - Change from incorrect "label:write" permission to "Maintain role or higher" - Workspace labels (used by this node) can be created by Maintain role - Resource labels (for cost tracking) require Admin/Owner roles This reduces code duplication and provides accurate guidance to users about required token permissions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 0c32b07 commit b476846

File tree

2 files changed

+20
-33
lines changed

2 files changed

+20
-33
lines changed

nodes/workflow-launch.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
: Launchpad (string) : The human-readable name of a pipeline in the launchpad to launch. Supports autocomplete.
6767
: Run name (string) : Custom name for the workflow run (optional, defaults to auto-generated name).
6868
: Resume from (string) : Workflow ID from a previous run to resume (optional). Can be extracted from workflow monitor output using `msg.workflowId`.
69-
: Labels (string) : Comma-separated label names to assign to the workflow run (optional), e.g., `production,rnaseq,urgent`. Labels are automatically created if they don't exist (requires API token with `label:write` permission). The node resolves names to IDs automatically.
69+
: Labels (string) : Comma-separated label names to assign to the workflow run (optional), e.g., `production,rnaseq,urgent`. Labels are automatically created if they don't exist (requires API token with Maintain role or higher). The node resolves names to IDs automatically.
7070
: Parameters (array) : Individual parameter key-value pairs added via the editable list. Each parameter can be configured with a name and a value of any type (string, number, boolean, JSON, etc.). These take highest precedence when merging.
7171
: Params JSON (object) : A JSON object containing multiple parameters to merge with the launchpad's default parameters. Merged before individual parameters.
7272
: Workspace ID (string) : Override the workspace ID from the Seqera config node (optional).
@@ -107,10 +107,10 @@
107107
Labels help organize and track workflow runs in your workspace. Simply provide comma-separated label names (e.g., `production,rnaseq,urgent`) and the node will:
108108

109109
1. Check if labels exist in the workspace
110-
2. Automatically create missing labels (requires `label:write` permission)
110+
2. Automatically create missing labels (requires Maintain role or higher)
111111
3. Resolve names to IDs and apply them to the workflow run
112112

113-
**Token permissions:** Your API token needs `label:write` permission to create labels automatically. Without this permission, you'll need to create labels manually in the Seqera UI first.
113+
**Token permissions:** Your API token needs Maintain role or higher to create labels automatically. Without sufficient permissions, you'll need to create labels manually in the Seqera UI first.
114114

115115
### References
116116

nodes/workflow-launch.js

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ module.exports = function (RED) {
165165

166166
if (errorStatus === 403) {
167167
throw new Error(
168-
`Cannot create label '${labelName}': API token missing 'label:write' permission. Add this permission or create labels manually in Seqera UI.`,
168+
`Cannot create label '${labelName}': API token requires 'Maintain' role or higher. Use a token with sufficient permissions or create labels manually in Seqera UI.`,
169169
);
170170
} else {
171171
throw new Error(`Failed to create label '${labelName}': ${errorDetail}`);
@@ -289,21 +289,6 @@ module.exports = function (RED) {
289289
body.launch.runName = runName.trim();
290290
}
291291

292-
// Resolve label names to IDs if provided, creating labels as needed
293-
if (labels) {
294-
body.launch = body.launch || {};
295-
try {
296-
const labelIds = await resolveLabelIds(labels, workspaceId, baseUrl, msg);
297-
if (labelIds.length > 0) {
298-
body.launch.labelIds = labelIds;
299-
}
300-
} catch (errLabels) {
301-
node.error(`Failed to resolve labels: ${errLabels.message}`, msg);
302-
node.status({ fill: "red", shape: "ring", text: `error: ${formatDateTime()}` });
303-
return;
304-
}
305-
}
306-
307292
// Resume from a previous workflow if workflow ID is provided
308293
// This fetches the workflow's launch config and sessionId, then relaunches with resume enabled
309294
if (resumeWorkflowId && resumeWorkflowId.trim && resumeWorkflowId.trim()) {
@@ -370,20 +355,6 @@ module.exports = function (RED) {
370355
resumeLaunch.runName = runName.trim();
371356
}
372357

373-
// Resolve label names to IDs if provided, creating labels as needed
374-
if (labels) {
375-
try {
376-
const labelIds = await resolveLabelIds(labels, workspaceId, baseUrl, msg);
377-
if (labelIds.length > 0) {
378-
resumeLaunch.labelIds = labelIds;
379-
}
380-
} catch (errLabels) {
381-
node.error(`Failed to resolve labels for resume: ${errLabels.message}`, msg);
382-
node.status({ fill: "red", shape: "ring", text: `error: ${formatDateTime()}` });
383-
return;
384-
}
385-
}
386-
387358
body.launch = resumeLaunch;
388359
} catch (errResume) {
389360
node.error(`Failed to fetch workflow launch config for resume: ${errResume.message}`, msg);
@@ -392,6 +363,22 @@ module.exports = function (RED) {
392363
}
393364
}
394365

366+
// Resolve label names to IDs if provided, creating labels as needed
367+
// Applied after both regular launch and resume paths have set up body.launch
368+
if (labels) {
369+
body.launch = body.launch || {};
370+
try {
371+
const labelIds = await resolveLabelIds(labels, workspaceId, baseUrl, msg);
372+
if (labelIds.length > 0) {
373+
body.launch.labelIds = labelIds;
374+
}
375+
} catch (errLabels) {
376+
node.error(`Failed to resolve labels: ${errLabels.message}`, msg);
377+
node.status({ fill: "red", shape: "ring", text: `error: ${formatDateTime()}` });
378+
return;
379+
}
380+
}
381+
395382
// Build URL with query params
396383
let url = `${baseUrl.replace(/\/$/, "")}/workflow/launch`;
397384
const qs = new URLSearchParams();

0 commit comments

Comments
 (0)