Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -722,9 +722,11 @@ tw roles permissions -o my-org
tw roles add -o my-org -n launcher -d "Launch only" -p <permission>,<permission>
```

### Teams and quotas
### Teams, IdP groups and SCIM

- `tw teams view|update|workspaces`: view a team, update its name or description, and list its workspaces.
- `tw teams view|update|workspaces`: view a team, update its name, description or linked IdP group (`--idp-group`, `--unlink-idp-group`), and list its workspaces.
- `tw organizations idp-groups list|add|delete`: manage the identity provider groups available to the organization.
- `tw organizations scim view|create-token|rotate-token|revoke-token`: manage SCIM provisioning.
- `tw organizations quotas` and `tw members roles -u <user>`: view organization quotas and a member's workspace roles.

## Personal access
Expand Down Expand Up @@ -764,10 +766,19 @@ tw lineage resolve -w my-org/my-workspace --session-id <session-id> --run-name <
tw lineage upstream -w my-org/my-workspace -i <lid>
```

## Audit logs

Run `tw audit-logs -h` to view the supported operations: `list`, `view`, and `export`. These commands require a root user.

```bash
tw audit-logs export --after 2026-09-01T00:00:00Z --before 2026-09-30T23:59:59Z -o september.csv
```

## Other additions

- `tw compute-envs enable|disable`: enable or disable a compute environment.
- `tw compute-envs add`:
- Intelligent Compute options on `aws-cloud`, `azure-cloud`, and `google-cloud`. Run `tw compute-envs add <platform> -h` for the options each platform supports.
- AWS Batch: CloudWatch log group and DRAGEN options.
- AWS Cloud: `--log-group`. Google Cloud: `--project-id`.
- HPC platforms: `--propagate-head-job-options`.
Expand Down
173 changes: 173 additions & 0 deletions conf/reflect-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,12 @@
"allDeclaredMethods":true,
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.AuditLogsCmd",
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true,
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.CollaboratorsCmd",
"allDeclaredFields":true,
Expand Down Expand Up @@ -395,6 +401,40 @@
"allDeclaredMethods":true,
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.auditlogs.AuditLogsFilterOptions",
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true,
"fields":[{"name":"after"}, {"name":"before"}],
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.auditlogs.AuditLogsFilterOptions$DateTimeConverter",
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true,
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.auditlogs.ExportCmd",
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true,
"fields":[{"name":"filter"}, {"name":"output"}, {"name":"state"}],
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.auditlogs.ListCmd",
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true,
"fields":[{"name":"filter"}, {"name":"max"}, {"name":"pageToken"}],
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.auditlogs.ViewCmd",
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true,
"fields":[{"name":"id"}],
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.collaborators.AbstractCollaboratorsCmd",
"allDeclaredFields":true,
Expand Down Expand Up @@ -1735,6 +1775,12 @@
"allDeclaredMethods":true,
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.organizations.IdpGroupsCmd",
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true,
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.organizations.ListCmd",
"allDeclaredFields":true,
Expand Down Expand Up @@ -1766,6 +1812,12 @@
"fields":[{"name":"organizationRefOptions"}],
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.organizations.ScimCmd",
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true,
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.organizations.UpdateCmd",
"allDeclaredFields":true,
Expand All @@ -1778,6 +1830,62 @@
"allDeclaredMethods":true,
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.organizations.idpgroups.AddCmd",
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true,
"fields":[{"name":"name"}, {"name":"organizationRef"}],
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.organizations.idpgroups.DeleteCmd",
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true,
"fields":[{"name":"group"}, {"name":"organizationRef"}],
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.organizations.idpgroups.DeleteCmd$GroupRef",
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true,
"fields":[{"name":"id"}, {"name":"name"}],
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.organizations.idpgroups.ListCmd",
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true,
"fields":[{"name":"organizationRef"}],
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.organizations.scim.CreateTokenCmd",
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true,
"fields":[{"name":"organizationRef"}],
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.organizations.scim.RevokeTokenCmd",
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true,
"fields":[{"name":"organizationRef"}],
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.organizations.scim.RotateTokenCmd",
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true,
"fields":[{"name":"organizationRef"}],
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.organizations.scim.ViewCmd",
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true,
"fields":[{"name":"organizationRef"}],
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.participants.AbstractParticipantsCmd",
"allDeclaredFields":true,
Expand Down Expand Up @@ -2418,6 +2526,13 @@
"fields":[{"name":"description"}, {"name":"idpGroup"}, {"name":"newName"}, {"name":"organizationRef"}, {"name":"ref"}],
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.teams.UpdateCmd$IdpGroup",
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true,
"fields":[{"name":"name"}, {"name":"unlink"}],
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"io.seqera.tower.cli.commands.teams.ViewCmd",
"queryAllDeclaredMethods":true,
Expand Down Expand Up @@ -2642,6 +2757,24 @@
"allDeclaredMethods":true,
"allDeclaredConstructors":true
},
{
"name":"io.seqera.tower.cli.responses.auditlogs.AuditLogView",
"allDeclaredFields":true,
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true
},
{
"name":"io.seqera.tower.cli.responses.auditlogs.AuditLogsExported",
"allDeclaredFields":true,
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true
},
{
"name":"io.seqera.tower.cli.responses.auditlogs.AuditLogsList",
"allDeclaredFields":true,
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true
},
{
"name":"io.seqera.tower.cli.responses.collaborators.CollaboratorsList",
"allDeclaredFields":true,
Expand Down Expand Up @@ -2977,6 +3110,24 @@
"allDeclaredMethods":true,
"allDeclaredConstructors":true
},
{
"name":"io.seqera.tower.cli.responses.organizations.IdpGroupAdded",
"allDeclaredFields":true,
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true
},
{
"name":"io.seqera.tower.cli.responses.organizations.IdpGroupDeleted",
"allDeclaredFields":true,
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true
},
{
"name":"io.seqera.tower.cli.responses.organizations.IdpGroupsList",
"allDeclaredFields":true,
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true
},
{
"name":"io.seqera.tower.cli.responses.organizations.OrganizationQuotasView",
"allDeclaredFields":true,
Expand Down Expand Up @@ -3019,6 +3170,28 @@
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true
},
{
"name":"io.seqera.tower.cli.responses.organizations.ScimConfigView",
"allDeclaredFields":true,
"allDeclaredMethods":true,
"allDeclaredConstructors":true,
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true
},
{
"name":"io.seqera.tower.cli.responses.organizations.ScimTokenCreated",
"allDeclaredFields":true,
"allDeclaredMethods":true,
"allDeclaredConstructors":true,
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true
},
{
"name":"io.seqera.tower.cli.responses.organizations.ScimTokenRevoked",
"allDeclaredFields":true,
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true
},
{
"name":"io.seqera.tower.cli.responses.participants.ParticipantAdded",
"allDeclaredFields":true,
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/io/seqera/tower/cli/Tower.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import io.seqera.tower.cli.commands.AbstractCmd;
import io.seqera.tower.cli.commands.AccessTokensCmd;
import io.seqera.tower.cli.commands.ActionsCmd;
import io.seqera.tower.cli.commands.AuditLogsCmd;
import io.seqera.tower.cli.commands.CollaboratorsCmd;
import io.seqera.tower.cli.commands.ComputeEnvsCmd;
import io.seqera.tower.cli.commands.CredentialsCmd;
Expand Down Expand Up @@ -63,6 +64,7 @@
subcommands = {
AccessTokensCmd.class,
ActionsCmd.class,
AuditLogsCmd.class,
CollaboratorsCmd.class,
ComputeEnvsCmd.class,
CredentialsCmd.class,
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/io/seqera/tower/cli/commands/AbstractApiCmd.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import io.seqera.tower.ApiResponse;
import io.seqera.tower.Pair;
import io.seqera.tower.api.ActionsApi;
import io.seqera.tower.api.AdminApi;
import io.seqera.tower.api.AvatarsApi;
import io.seqera.tower.api.CompatibilityApi;
import io.seqera.tower.api.ComputeEnvsApi;
Expand Down Expand Up @@ -69,6 +70,7 @@
import io.seqera.tower.model.ComputeEnvResponseDto;
import io.seqera.tower.model.Credentials;
import io.seqera.tower.model.DataStudioQueryAttribute;
import io.seqera.tower.model.IdpGroupEntry;
import io.seqera.tower.model.ListComputeEnvsResponseEntry;
import io.seqera.tower.model.ListPipelineVersionsResponse;
import io.seqera.tower.model.ListWorkspacesAndOrgResponse;
Expand Down Expand Up @@ -215,6 +217,10 @@ protected ActionsApi actionsApi() throws ApiException {
return actionsApi == null ? new ActionsApi(apiClient()) : actionsApi;
}

protected AdminApi adminApi() throws ApiException {
return new AdminApi(apiClient());
}

protected AvatarsApi avatarsApi() throws ApiException {
return avatarsApi == null ? new AvatarsApi(apiClient()) : avatarsApi;
}
Expand Down Expand Up @@ -580,6 +586,14 @@ protected OrgAndWorkspaceDto findOrganizationByRef(String organizationRef) throw
return orgAndWorkspaceDbDtoList.stream().findFirst().orElseThrow(() -> new OrganizationNotFoundException(organizationRef));
}

protected IdpGroupEntry findIdpGroupByName(Long orgId, String displayName) throws ApiException {
return orgsApi().listOrganizationIdpGroups(orgId).getGroups()
.stream()
.filter(group -> Objects.equals(group.getDisplayName(), displayName))
.findFirst()
.orElseThrow(() -> new TowerException(String.format("IdP group '%s' not found in organization '%d'", displayName, orgId)));
}

protected List<Long> findOrCreateLabels(Long wspId, List<Label> labels) throws ApiException {
if (labels != null && !labels.isEmpty()) {
LabelsFinder finder = new LabelsFinder(labelsApi());
Expand Down
35 changes: 35 additions & 0 deletions src/main/java/io/seqera/tower/cli/commands/AuditLogsCmd.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2021-2026, Seqera.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


package io.seqera.tower.cli.commands;

import io.seqera.tower.cli.commands.auditlogs.ExportCmd;
import io.seqera.tower.cli.commands.auditlogs.ListCmd;
import io.seqera.tower.cli.commands.auditlogs.ViewCmd;
import picocli.CommandLine.Command;

@Command(
name = "audit-logs",
description = "Inspect the installation audit logs. Requires a root user (platform administrator).",
subcommands = {
ListCmd.class,
ViewCmd.class,
ExportCmd.class,
}
)
public class AuditLogsCmd extends AbstractRootCmd {
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@

import io.seqera.tower.cli.commands.organizations.AddCmd;
import io.seqera.tower.cli.commands.organizations.DeleteCmd;
import io.seqera.tower.cli.commands.organizations.IdpGroupsCmd;
import io.seqera.tower.cli.commands.organizations.ListCmd;
import io.seqera.tower.cli.commands.organizations.QuotasCmd;
import io.seqera.tower.cli.commands.organizations.ScimCmd;
import io.seqera.tower.cli.commands.organizations.UpdateCmd;
import io.seqera.tower.cli.commands.organizations.ViewCmd;
import picocli.CommandLine;
Expand All @@ -34,6 +36,8 @@
UpdateCmd.class,
ViewCmd.class,
QuotasCmd.class,
IdpGroupsCmd.class,
ScimCmd.class,
}
)
public class OrganizationsCmd extends AbstractRootCmd {
Expand Down
Loading
Loading