Skip to content

feat: support Platform API 1.101 features (catch-up backlog) - #685

Merged
cristianrcv merged 28 commits into
masterfrom
feat/NOTASK-api-1.101-catch-up
Oct 7, 2026
Merged

cristianrcv merged 28 commits into
masterfrom
feat/NOTASK-api-1.101-catch-up

Conversation

@cristianrcv

@cristianrcv cristianrcv commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Exposes API features that were already in Platform API 1.101.0 or earlier (1.101.0 is the oldest spec in tower-sdk-gencode's history), which tw never surfaced.

This is one PR in a stack that catches tw up with Platform API 1.230.0, one PR per API version that introduced the features, then one PR per topic for agents and actions. Each PR adds the items whose API elements all exist in that version.

Changes

  • feat(compute-envs): add CloudWatch log group and DRAGEN options to AWS Batch (5642525)
  • feat(compute-envs): add --propagate-head-job-options to HPC platforms (ab7c9dc)
  • feat(compute-envs): add --data-retention-policy to Seqera Compute (4ee5cd4)
  • feat(compute-envs): add log group and project ID cloud options (2cc169a)
  • feat(compute-envs): add enable and disable commands (be7c471)
  • feat(launch): add --tower-config option (e0c5267)
  • feat(runs): add 'tw runs star' and 'tw runs unstar' (2a19581)
  • feat(runs): delete several runs in one 'tw runs delete' (b331c35)
  • feat(runs): add 'tw runs view log' to print a run or task execution log (b21111e)
  • feat(runs): page through run logs with --next (45a4efa)
  • fix(pipelines): keep labels and icon on 'tw pipelines update' (b32f4f3)
  • feat(pipelines): add 'tw pipelines schema' to read a pipeline's parameter schema (4fa3264)
  • feat(studios): add extend and rename-checkpoint (c968b07)
  • feat(studios): show progress warnings while waiting (8b87123)
  • feat(data-links): add delete-content and download-script (98bbddb)
  • fix(data-links): stop printing a Jersey warning on delete-content (7adcc8f)
  • feat(datasets): disable dataset versions (23b5cc2)
  • feat(teams): add view, update and workspaces commands (52edfd3)
  • fix(teams): find teams by name beyond the first page (e6b6978)
  • feat(organizations): add quotas command (7bcb946)
  • feat(access-tokens): add access-tokens list, add and delete commands (e9377d3)
  • feat(managed-identities): add managed identities and their SSH credentials (03a046c)
  • fix(managed-identities): list credentials for every member (a8b1ecc)
  • test: capture the native binary's output verbatim (65ce579)
  • docs: document the commands and options added for API 1.101.0 (f9f5838)
  • build(native): register reflection metadata for the new commands (49b33e3)
  • build(native): register every field of the new response classes (72a4526)

Notes for review

  • Changes to existing behaviour:
    • pipelines update now sends back the existing labels and icon. Platform's update replaces both, so they were silently dropped before.
    • Looking up a team by name now finds teams beyond the first page of 50, in both teams and participants.
  • Jersey warning: data-links delete-content is a DELETE with a body. Jersey logs Entity must be null for http method DELETE to stderr through JUL, so that logger is raised to SEVERE.
  • Test harness: BaseCmdTest.execBinary now copies the native binary's output verbatim. Re-joining lines with println turned line feeds inside printed content into CRLF on Windows.
  • conf/reflect-config.json:
    • backfills entries that master was already missing for 17 existing classes (e.g. computeenvs.ValidateCmd, RunView);
    • registers allDeclaredFields for the new responses, so -o json doesn't lose fields in the native binary.
  • Adaptations for SDK 1.200.0: the SDK types LogPage.entries as Object (the spec says Iterator_String_). Managed-identity 409 bodies are parsed as DeleteCredentialsConflictResponse.

Verification

  • ./gradlew test: 819 tests, 0 failures. Every new command and option has MockServer tests that assert the request (method, path, query, body) and the output.
  • Each item was checked against the OpenAPI spec of this version and the previous one (tower-sdk-gencode history) to confirm where it first appears.
  • The native binary built from this branch passed the full test suite (TOWER_CLI=build/native/nativeCompile/tw ./gradlew cleanTest test).

🤖 Generated with Claude Code

@cristianrcv
cristianrcv marked this pull request as draft October 2, 2026 17:25
@cristianrcv

Copy link
Copy Markdown
Contributor Author

@educalleja @t0randr @swampie @jonmarti Rob Syme reported a bug on CLI that some missing features were returning a 400. Within that context I reviewed all the SDK bumps against the features supported by the CLI and opened a bunch of pull requests. While the other ones can be targgeted per SDK bump, this targets all the old features that the CLI does not support.

Before doing the effort of splitting this into PRs, do you know if supporting these features is needed in the CLI? Are the users on your use cases missing or complaining about these missing features?

@cristianrcv
cristianrcv added this pull request to stack #693 October 2, 2026 18:17
@cristianrcv
cristianrcv marked this pull request as ready for review October 5, 2026 09:38
@cristianrcv
cristianrcv removed this pull request from stack #693 October 5, 2026 16:19
@cristianrcv
cristianrcv added this pull request to stack #705 October 5, 2026 16:20
@swampie

swampie commented Oct 5, 2026

Copy link
Copy Markdown
Member

Staging test report — full stack, cloud.stage-seqera.io (Platform API 1.231.0)

Every PR in the stack was tested against its own native binary, built from its own branch head, against live staging in org seqerakit (user is a root user). No mock servers — all results below are real API calls.

Note on numbering. The stack was re-created at 16:18 UTC while testing was in progress, so the PRs I tested as #687–#692 are now closed and replaced, with agents and actions split out into their own PRs. I verified that every defective code path below is present verbatim in the replacement branches, so the findings carry over unchanged. Mapping used throughout:

tested as now notes
#685 #685 unchanged
#686 #686 unchanged
#687 #697 bucket actions moved to #703
#688 #703 cron actions folded into the actions PR
#689 #698
#690 #699 + #702 agents extracted to #702
#691 #700 + #702 agents extracted to #702
#692 #701 + #702 + #703

PR health at a glance

PR Area Verdict
#685 API 1.101 catch-up ⚠️ had a blocker — now fixed (B1, merged as ed484abe)
#686 1.113 — SSH keys ✅ healthy — no defects found
#697 1.145 — roles, folder mounts, linked datasets ✅ healthy (1 cosmetic nit, m4)
#698 1.167 — audit logs, IdP/SCIM, Intelligent Compute 🛑 blocker — B2
#699 1.190 — studio stars, Nextflow versions 🛑 blocker — B4 (fixed by ed484abe, not yet in this line)
#700 1.200 — lineage, studio logs, IC limits 🛑 blocker — B3
#701 1.230 — SDK bump, service accounts, federation ⚠️ major — M2
#702 agents command group ✅ healthy — and it resolves M1
#703 actions: bucket/cron/pipeline-status + triggers ⚠️ major — M3 (server-side), plus m1

Healthy: #686, #697, #702. Everything else has at least one open issue.


⚠️ Read first: the auth fix is not in the rest of the stack

ed484abe (the B1/B4 fix, merged into feat/NOTASK-api-1.101-catch-up) is not an ancestor of any other branch in the stack, including #686's head — they all fork from 72a45266, which predates the merge.

ed484abe present in: feat/NOTASK-api-1.101-catch-up  only
            absent in: #686, #697, #698, #699, #700, #701, #702, #703

So tw runs star, tw runs unstar and tw info versions are still broken everywhere downstream until #686 is rebased onto the updated #685 and the rebase propagates. Nothing is wrong with the fix — this is purely propagation.


🛑 Blocking defects

B2 — tw audit-logs list / view cannot parse a successful response — #698

The request succeeds (HTTP 200, valid JSON). The CLI then fails to deserialize it:

JsonMappingException: AuditLogTargetStateNewState cannot be null
  ListAuditLogV2Response["auditLogs"]→[0]→["target"]→["state"]→AuditLogTargetState["previousState"]

The server returns "state":{"previousState":null,"newState":null,…}. AuditLogTargetStateNewState is a generated oneOf wrapper (34 variants) whose deserializer has:

public AuditLogTargetStateNewState getNullValue(DeserializationContext ctx) throws JsonMappingException {
    throw new JsonMappingException(ctx.getParser(), "AuditLogTargetStateNewState cannot be null");
}

— unconditional, the generator's pattern for a oneOf not marked nullable: true.

  • Frequency: 41 of 41 sampled logs have previousState: null. This is the normal case, not an edge case.
  • Not fixed by the SDK bump — reproduced identically against SDK 1.230.0 via a direct Jackson probe.
  • audit-logs export is unaffected (CSV is rendered server-side) — usable workaround today.
  • Not a permissions issue: the export CSV shows actorIsRoot: true.
  • User-facing symptom is misleading: it reports Connection error. Check the connection using 'tw info' when the network is fine.

Fix options: mark those two fields nullable: true in the spec (fixes all SDK consumers); or override the null handling CLI-side — there is precedent in AbstractApiCmd, which already registers TaskExitMixin for a structurally identical SDK mismatch.

B3 — tw lineage view returns 404 for every record — #700

Against the same encoded lid, same workspace, same token:

endpoint status
/lineage/{lid} ← used by the default view 404
/lineage/{lid}/summary 200
/lineage/{lid}/upstream 200
/lineage/{lid}/downstream 200

Reproduced for FileOutput, TaskRun and WorkflowRun. The record is demonstrably present — three sibling routes resolve the identical identifier.

  • Workaround: tw lineage view --summary works.
  • Ruled out — path encoding. The CLI emits a double-encoded segment (%253A, %252F), which looked like the obvious culprit. It isn't: single-encoded, double-encoded and literal-slash forms all 404, and the siblings succeed with the identical double-encoded segment.
  • Ruled out — response shape as a diagnostic. Every 404 on this API is empty-bodied, including known-good routes with bogus ids, so it can't distinguish a missing route from a missing record.
  • Undetermined from the client: whether /lineage/{lid} is undeployed at 1.231.0, or deployed but unable to materialise the record. The --summary help text hints at a mechanism — summary comes from the lineage index, while the full record's recordUri is an S3 object (s3://seqera-lineage-…/.data.json). Needs someone with server/bucket visibility.
  • Caveat: all 1000 lineage records on staging live in one workspace (64430228002560), so a workspace-specific condition can't be excluded.

B4 — tw info versions sends no Authorization header — #699

Same root cause as B1: NextflowApi.nextflowVersions passes null authNames, and ApiClient.invokeAPI skips authentication entirely when that array is null rather than falling back.

Confirmed by curl: GET /platform/versions → 401 without auth, 200 with auth.

Already fixed by ed484abe — but see the propagation note above. This was the third command hit by this root cause, which is why that fix defaults auth generally instead of special-casing the star endpoints.


⚠️ Major

M2 — the documented service-account workflow does not work — #701

#701's own USAGE.md says: "Add one to a workspace with tw participants add -t MEMBER -n <name>." That command fails:

ERROR: Service accounts cannot be added as workspace collaborators

AddCmd's MEMBER branch calls findOrganizationMemberByName, falling back to userNameOrEmail on MemberNotFoundException. Service accounts are not returned by /orgs/{id}/members (?search=… → {"members":[],"totalSize":0}), so the lookup always throws and the fallback sends a shape the server rejects for service accounts.

The API supports it — PUT …/participants/add with {"memberId":227302255131700} → 200, userType: SERVICE_ACCOUNT. That member id is already surfaced by tw service-accounts view ("Member ID").

This blocks the service-account → agent flow end to end; I had to add the participant via raw API to test agents at all. participants update -t MEMBER is unaffected (it resolves against existing participants).

M3 — tw actions add pipeline-status fails server-side — #703

HTTP 400 {"message":"Unexpected error while processing request - Error ID: …"}

Reproduced via raw curl, identically, for three different watched-pipeline ids including a bogus one — so the CLI's request is well-formed and this is a platform failure, not a CLI defect. The body sent looks correct:

{"launch":{…},"name":"…","pipelineStatus":{"pipelineId":196256443154544,"runStatus":"FAILED"},"source":"pipeline_status"}

Error IDs for the platform team: 3iars46Gfj1Y1MD4Px6wvt, 7TirUNr5EOFtlC7mpzENm9, 1w0X4z3ZTcx9VCrNQG9ZWp, 2EYZrnbdzxBCg6m7VKskJk.

Consequence: actions add pipeline-status is unverified, and actions triggers list|view could only be exercised against an action with no triggers.

M1 — agents add was unusable before the agents split — resolved in #702

The server requires serviceAccountId; SDK 1.200.0's CreateAgentRequest has no such field, so it was unsettable in the old #690/#691. SDK 1.230.0 adds it and #702 adds the matching --service-account-id. Verified working: agent created, agents view shows Service account | cli-test-sa. Recorded only because it meant the old 1.190/1.200 PRs could not be validated standalone — the split into #702 resolves that.


Minor

id issue where
m1 AbstractAddCmd.java:107 does catch (Exception e) and throws "Unable to add action for workspace '<ws>'", discarding the server body — e is never used. For a bad cron the server actually says {"message":"Cron expression contains 3 parts but we expect one of [5]"}. Pre-existing on master; cron makes it far more visible. #703
m2 Empty-body errors render as ERROR: error (seen on 403s from seqera-compute add, rename-checkpoint, bulk run delete; 404s from lineage). The response carries X-Request-Id, which could be surfaced. pre-existing
m3 actions list -w <ws> always prints Actions for <user> user: regardless of -w (ActionsList.java:54). pre-existing
m4 tw roles view -n nope → Role nope doesn't exist (double space). #697
m5 teams delete accepts only -i, while #685 added -n to teams view/update/workspaces. #685
m6 Latent: SDK AuditEventType lacks action_triggered, which the server emits (12 of 100 sampled logs). Currently masked by B2 — likely to surface as the next failure once B2 is fixed. Worth folding into the same spec pass. #698

What passed

Substantial parts of the stack are solid. Highlights verified end-to-end against staging:

Behaviour-changing fixes in #685 were regression-tested specifically, since those carry the most risk for existing users.


Not covered — stated explicitly rather than implied

Housekeeping: all test artifacts were removed and the engineering team was restored to its original admin role. One exception — an azure-cloud CE cli-kv (7g8TjHbBFHSZe3R4neH2rY) in seqerakit/megatest13 is stuck in CREATING and refuses deletion (Unable to delete a compute environment in CREATING state); it needs manual cleanup.


Suggested order of attack

  1. Propagate ed484abe — rebase feat: support Platform API 1.113 features (SSH keys) #686 so B1/B4 clear across the whole stack. Cheapest, unblocks three commands.
  2. B2 — spec nullable fix, or the CLI-side mixin workaround if you'd rather not wait.
  3. B3 and M3 — both need Platform-side investigation; Error IDs are above.
  4. M2 — resolve service accounts by member id in participants add.

🤖 Generated with Claude Code

@swampie

swampie commented Oct 6, 2026

Copy link
Copy Markdown
Member

@cristianrcv the commit claude references above is the small correction I did to the tip of the stack but the actual fix would be the one you did in the platform api. So feel free to ignore

cristianrcv and others added 4 commits October 7, 2026 11:32
…S Batch

The Platform API (at least since 1.101.0) accepts AwsBatchConfig.logGroup
and the ForgeConfig DRAGEN fields (dragenEnabled, dragenAmiId,
dragenInstanceType), and the web UI exposes them, but tw never set them.

- --log-group for 'aws-batch forge' and 'aws-batch manual'
- --dragen, --dragen-ami-id, --dragen-instance-type for 'aws-batch forge'

DRAGEN settings are checked client-side because the AMI and instance type
are only validated during asynchronous forge creation, so a missing value
would otherwise surface later as an errored compute environment.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Slurm, LSF, Univa Grid Engine, Altair PBS and Moab configs have accepted
propagateHeadJobOptions since at least API 1.101.0, and the web UI shows it
as 'Apply head job submit options to compute jobs'. tw never set it, so
CLI-created HPC environments could not pass the head job submit options to
the Nextflow compute jobs (process.clusterOptions).

The option requires --head-job-options: Platform reads the head job options
unguarded when propagation is on, so the combination is rejected up front.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
SeqeraComputeConfig.defaultDataRetentionPolicy (API 1.101.0 or earlier)
asks Seqera Compute to put a lifecycle policy on the bucket it creates,
deleting intermediate files after 28 days. The web UI shows it as
'Automatic Data Retention Policy' and turns it on by default; tw never sent
it, so CLI-created environments always got a bucket without the policy.

The flag is opt-in, which keeps the current tw behaviour when it is not
given.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Two cloud config fields accepted by the Platform API (at least since
1.101.0) were never set by tw:
- aws-cloud --log-group (AwsCloudConfig.logGroup): CloudWatch Logs
  group for the CE; Platform defaults it to /seqera/platform.
- google-cloud --project-id (GoogleCloudConfig.projectId): written as
  google.project and used to qualify short network/subnetwork names.
  Platform does not fill it from the credentials for Google Cloud.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
cristianrcv and others added 22 commits October 7, 2026 11:32
POST/DELETE /workflow/{workflowId}/star have been in the API since at
least 1.101.0, but runs could only be starred from the web UI. Starring
is per user, so a starred run surfaces in that user's run list in the UI.

Unstarring a run that is not starred is a 404 on Platform; it is
reported like any other API error rather than reinterpreted.

The starred state is not added to 'tw runs view': it would cost an extra
request, and the SDK types GET /workflow/{id}/star as
CreateWorkflowStarResponse (workflowId only) although Platform returns
DescribeWorkflowStarResponse with a 'starred' flag, so the flag cannot be
read through the SDK.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
POST /workflow/delete (deleteWorkflowMany, in the API since at least
1.101.0) deletes a list of runs and reports the ones it could not delete,
but tw only took one id, so cleaning up runs meant one invocation per
run.

'-i' now accepts several ids, repeated or comma-separated. A single id
keeps calling DELETE /workflow/{id}, so its output and errors are
unchanged. Several ids go through the bulk endpoint with --force passed
on; each run is reported as deleted or not, and the command exits 1 when
any could not be deleted so scripts notice partial failures. Platform
caps the list size and rejects longer ones with a 400.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
'tw runs view download' and 'tw runs dump' fetch log files through
/workflow/{id}/download, which serves the files the run leaves in its
work directory. GET /workflow/{id}/log and /log/{taskId} (in the API
since at least 1.101.0) are what the UI's Execution log tab uses: Platform
reads the compute platform's live log stream when the provider has one
and only falls back to the output file otherwise, so they also show the
output of a run that is still going. tw had no way to reach them.

'tw runs view -i <id> log' prints the Nextflow head job output and
'-t <taskId>' the task output. Platform's own notice (for example why the
log could not be read) is shown after the entries, and a truncated page
says so and points to 'download' for the complete file.

Only the first page is fetched. Following the cursor would turn the
command into a 'tail -f', and how the cursor behaves differs per compute
platform, so that is left for when someone needs it.

Up to SDK 1.200.0 the spec types LogPage.entries as an Iterator object,
so the SDK exposes it as Object; Platform sends a JSON array of strings,
which LogCmd reads back as a list.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Live log streams such as CloudWatch return one page per call (up to 10k events or 1 MB) without
flagging truncation. So 'runs view log' printed the first page of a long log as if it were all of
it. Print the forward cursor and accept it with --next (the 'next' query parameter of
GET /workflow/{id}/log, in the API since at least 1.101.0). An empty page ends the hint, because
CloudWatch keeps returning a cursor at the end of the stream.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The update sent no labelIds and no icon. Platform's update replaces the
pipeline's labels with labelIds; the API docs for both PUT
/pipelines/{id} and POST /pipelines/{id}/versions/{versionId} say a null
or omitted labelIds removes existing labels. It also sets the icon to
the request value and, when that is null, recomputes it from the
repository, so an uploaded icon was replaced. The web form sends back
the current labels and icon; tw now does the same, reading the labels
through describePipeline's 'labels' attribute.

Found while checking whether moving to updatePipeline (PUT
/pipelines/{id}) would gain anything. It would not: both endpoints call
the same PipelineService.updatePipeline, and PUT is the versionId=null
case, which only adds auto-promoting a new draft version to default.
tw already handles that, with --allow-draft on top.

The label loss is inferred from the Platform source and API docs, not
reproduced against a live Platform: LabelRefServiceImpl.applyLabelsToEntities
evaluates labelIds.contains(...) for each existing label.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…eter schema

GET /pipelines/{pipelineId}/schema (describePipelineSchema, in the API
since at least 1.101.0) returns the schema Platform uses to render a
pipeline's launch form: the custom schema attached to the launch
configuration if there is one, otherwise the repository's
nextflow_schema.json. tw could attach a custom schema
('tw pipeline-schemas add', 'tw pipelines add --pipeline-schema-id') but
never read one back, and had no way to see which parameters a pipeline
takes before writing a --params-file.

'tw pipelines schema -n <name>' prints the schema; '--params' prints the
parameter values the pipeline launches with instead (pipeline defaults
merged with the stored launch parameters). --version-id/--version-name
select a version, as in 'tw pipelines view'. Platform answers 204 when it
cannot resolve a schema; that is reported as an error rather than empty
output.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Platform API (at least since 1.101.0) exposes studio operations that tw
never wired up: lifespan extension (POST /studios/{sessionId}/lifespan)
and checkpoint renaming (PUT /studios/{sessionId}/checkpoints/{checkpointId}).
This adds 'tw studios extend|rename-checkpoint' so CLI users can do what
the UI already does.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
DataStudioProgressStep.warnings (in the API since at least 1.101.0;
e.g. cross-region data, failed checkpoint mounts) were never shown. They
are now printed once each while waiting on a studio with '--wait'.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Two data-explorer operations available since API 1.101.0 had no tw
command:

- 'tw data-links delete-content' calls DELETE /data-links/{id}/content
  to delete files (--file) and folders with their contents (--dir)
  while keeping the data link. The platform supports it for Seqera
  Compute data links only, and answers a partial deletion with 500 plus
  the failed items, which tw reports per item instead of a bare error.
- 'tw data-links download-script' calls GET
  /data-links/{id}/script/download and prints the cloud CLI commands
  (aws s3 cp, gcloud storage cp, ...) the UI offers for downloading.

GET /data-links/{id}/download/{filePath} is not added: it streams the
same file through the platform, with a size limit, that
'tw data-links download' already fetches through a signed URL.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
DELETE /data-links/{id}/content takes a request body. The SDK disables Jersey's HTTP compliance check,
so the body is sent, but Jersey still logs 'Entity must be null for http method DELETE' to stderr
through JUL on every call. In-process JVM tests don't capture System.err, so only the native binary
tests caught it. Raise that logger to SEVERE.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
POST /datasets/{id}/versions/{version}/disable (API 1.101.0 or earlier)
had no tw command, so a dataset version could only be disabled from the
UI.

- 'tw datasets disable-version --dataset-version <n>' disables it; the
  version can no longer be used for runs.
- 'datasets view ... versions' gains a Disabled column
  (DatasetVersionDto.disabled), so the result is visible.

DatasetsCmdTest now resets MockServer before each test, as the other
suites do, so request verifications are not affected by earlier tests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The API has long had describeOrganizationTeam, updateOrganizationTeam
and listWorkspacesByTeam (at least since 1.101.0), but tw could only
list, add and delete teams.

Add 'teams view', 'teams update' and 'teams workspaces', addressing a
team by --id or --name.

The update endpoint replaces name, description and avatar, so
'teams update' reads the team first and keeps unset fields. The team
response only carries the avatar download URL, so the avatar ID is
taken from its last path segment to avoid clearing the avatar.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
listOrganizationTeams pages by 50 by default, so looking a team up by name missed any team after
the first page. That affects the new teams view/update/workspaces commands and the existing
participants commands. Pass the name as the search filter and keep the exact-name match.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
describeOrganizationQuotas (/orgs/{orgId}/quotas, in the API since at
least 1.101.0) had no tw command.

Add 'tw organizations quotas' to show the organization limits.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The /tokens endpoints (API 1.101) let users manage their personal access
tokens, but tw could only consume one. 'tw access-tokens' now lists,
creates and deletes them by id or name. 'add' prints the token value
once, since Platform never returns it again. 'list' drops the deprecated
basicAuth field, which is a usable credential for legacy tokens.

DELETE /tokens/delete-all is not exposed: tw has no confirmation pattern
for bulk destructive operations, and it would also revoke the token tw
itself is running with.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…tials

Managed identities (/identities, API 1.101) are organization-level HPC
cluster connections (Altair PBS, LSF, Moab, Slurm, UGE): an owner
registers the login host and port once, and each member attaches their
own SSH key and Linux username as managed credentials. tw could not
manage either.

'tw managed-identities' adds list/add/view/update/delete, and
'tw managed-identities credentials' lists members' credentials and
adds, replaces or deletes them, for yourself or (as owner) for another
member. Deletions honour Platform's running-jobs check unless --force.

Two SDK gaps are worked around: the describe endpoint is modelled with
the wrong response shape, so identities are looked up in the list; and
the managed credentials metadata model lacks the required SSH userName,
so tw sends it through a small subclass.

SDK 1.200.0 generates a separate conflict type for each 409 response, so
the managed credentials 409 body is parsed as the credentials one (same
shape) to reuse CredentialsInUseException.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The endpoint returns one row per organization member, 50 by default. The list silently stopped at
50 members. Page through all rows, 100 at a time, in the helper that the list and the member
lookups share.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
execBinary read the binary's stdout line by line and re-printed each line with println. On Windows that turned every line feed inside printed content into CRLF. The new commands print server content verbatim (e.g. data-link download scripts), so their binary tests failed only on the Windows native job even though tw's output was right. Copy the raw streams instead, which matches how in-process tests capture output.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sections for teams and organization quotas, access tokens and managed
identities, plus a summary of the new options on existing commands.
Examples are plain commands in bash blocks (markdownlint MD014).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Both commands failed with "Unauthorized" against a live Platform, even
though the caller's token was valid and the same request made by hand
succeeded.

The workflow star endpoints are missing their security requirement in the
Platform OpenAPI spec, so the generated SDK passes no auth names for them.
ApiClient.invokeAPI skips authentication entirely when the auth name array
is null, rather than falling back to the configured scheme, so the request
went out with no Authorization header at all.

Default the auth names to BearerAuth when an operation declares none. This
routes through the SDK's own authentication, reusing the token already set
with setBearerToken.

In SDK 1.200.0 eleven operations declare no security: the three
*WorkflowStar ones, six GA4GH ones, ServiceInfoApi.info and
NextflowApi.nextflowVersions. The last two are genuinely public and the
GA4GH ones target the same host, so sending the token is harmless; a token
is always present by the time the client is built.

The existing star tests matched on method and path only, so an
unauthenticated request satisfied them. Assert the Authorization header
instead. The mock server is shared across the test class without a reset,
so the verification allows for the star requests other tests record.

This is a workaround, not the cure: the spec is still missing the security
block in SDK 1.230.0. Once that is fixed the override becomes a no-op.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…onflicts

These commands were written against SDK 1.200.0, where LogPage.entries was
typed Object and managed credentials had no conflict response of their
own. SDK 1.233.0 types the entries as List<String> and adds
DeleteManagedCredentialsConflictResponse, so drop both workarounds.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Entries for the new commands, option groups and responses, plus classes
master already lacked (e.g. computeenvs.ValidateCmd, RunView), taken from
a full test run under the GraalVM tracing agent. Response classes register
allDeclaredFields, since Jackson serializes every field for -o json.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@cristianrcv
cristianrcv force-pushed the feat/NOTASK-api-1.101-catch-up branch from ed484ab to 4148f96 Compare October 7, 2026 09:39
@cristianrcv
cristianrcv removed this pull request from stack #705 October 7, 2026 13:26
@cristianrcv

Copy link
Copy Markdown
Contributor Author

@swampie I have rebased this PR and the next 2 to master so that they can be merged independently. Major issues are addressed and I will address the minor issues as a follow-up once all is merged (it is easier to track and fix).

@cristianrcv
cristianrcv requested a review from a team October 7, 2026 13:42
@cristianrcv
cristianrcv merged commit 7ed8039 into master Oct 7, 2026
12 checks passed
cristianrcv added a commit that referenced this pull request Oct 7, 2026
Resolves conflicts with the API 1.101 catch-up (#685): the SSH keys section moves under 'Personal access' next to access tokens, and conf/reflect-config.json is master's file plus the ssh-keys entries, regenerated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@cristianrcv
cristianrcv deleted the feat/NOTASK-api-1.101-catch-up branch October 8, 2026 09:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants