Skip to content

Add MinIO storage profile command#323

Open
dkocher wants to merge 25 commits intomainfrom
issues/322
Open

Add MinIO storage profile command#323
dkocher wants to merge 25 commits intomainfrom
issues/322

Conversation

@dkocher
Copy link
Copy Markdown
Contributor

@dkocher dkocher commented Mar 30, 2026

@dkocher dkocher added this to the 1.0.0 milestone Mar 30, 2026
@dkocher dkocher requested a review from chenkins March 30, 2026 11:35
@dkocher dkocher added the cli label Mar 30, 2026
Copilot AI review requested due to automatic review settings March 30, 2026 11:35
@dkocher dkocher mentioned this pull request Mar 30, 2026
3 tasks

This comment was marked as outdated.

Copilot AI review requested due to automatic review settings April 1, 2026 20:49

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Contributor

@chenkins chenkins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add coverage for new command.

Copilot AI review requested due to automatic review settings April 2, 2026 07:49
@dkocher dkocher enabled auto-merge April 2, 2026 07:52
@dkocher dkocher requested a review from chenkins April 2, 2026 07:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

admin-cli/src/main/java/cloud/katta/cli/commands/storage/minio/MinIOSTSStorage.java:65

  • --accessbucketPolicyName (and the backing field accessbucketPolicyName) uses inconsistent casing compared to --createBucketPolicyName. For consistency and discoverability in CLI help, rename to --accessBucketPolicyName/accessBucketPolicyName. If the old flag was ever released, consider keeping --accessbucketPolicyName as an additional alias to avoid breaking existing scripts.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings April 3, 2026 09:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 7 comments.

Comments suppressed due to low confidence (1)

admin-cli/src/main/java/cloud/katta/cli/commands/storage/minio/MinIOSTSStorage.java:65

  • The option was renamed from --createbucketPolicyName to --createBucketPolicyName, which is a breaking CLI change for existing scripts. Consider accepting both spellings (aliases) for backward compatibility, and also align the casing of --accessbucketPolicyName (e.g., add --accessBucketPolicyName) for consistency.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Contributor

@chenkins chenkins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix MinIO.

@dkocher dkocher disabled auto-merge April 3, 2026 09:39
Copilot AI review requested due to automatic review settings April 3, 2026 09:53
Copilot AI review requested due to automatic review settings April 7, 2026 13:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +57 to +65
try (HttpClient client = HttpClient.newHttpClient()) {
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
if(response.statusCode() != 200) {
throw new IOException("Failed to fetch config from %s/api/config. HTTP status: %d".formatted(hubUrl, response.statusCode()));
}
var rootNode = new ObjectMapper().reader().readTree(response.body());
this.tokenUrl = rootNode.get("keycloakTokenEndpoint").asText();
this.authUrl = rootNode.get("keycloakAuthEndpoint").asText();
}
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HttpClient does not implement AutoCloseable, so try (HttpClient client = HttpClient.newHttpClient()) { ... } will not compile. Create the client without try-with-resources (or reuse a static client) and keep the try-with-resources only for resources that actually need closing.

Suggested change
try (HttpClient client = HttpClient.newHttpClient()) {
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
if(response.statusCode() != 200) {
throw new IOException("Failed to fetch config from %s/api/config. HTTP status: %d".formatted(hubUrl, response.statusCode()));
}
var rootNode = new ObjectMapper().reader().readTree(response.body());
this.tokenUrl = rootNode.get("keycloakTokenEndpoint").asText();
this.authUrl = rootNode.get("keycloakAuthEndpoint").asText();
}
HttpClient client = HttpClient.newHttpClient();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
if(response.statusCode() != 200) {
throw new IOException("Failed to fetch config from %s/api/config. HTTP status: %d".formatted(hubUrl, response.statusCode()));
}
var rootNode = new ObjectMapper().reader().readTree(response.body());
this.tokenUrl = rootNode.get("keycloakTokenEndpoint").asText();
this.authUrl = rootNode.get("keycloakAuthEndpoint").asText();

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +65
var rootNode = new ObjectMapper().reader().readTree(response.body());
this.tokenUrl = rootNode.get("keycloakTokenEndpoint").asText();
this.authUrl = rootNode.get("keycloakAuthEndpoint").asText();
}
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rootNode.get("keycloakTokenEndpoint") / get("keycloakAuthEndpoint") can return null if the config response is missing those fields, leading to an NPE on .asText(). Use path(...) and validate non-empty values (or throw a clear exception) before proceeding.

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +77
try {
Desktop.getDesktop().browse(uri);
}
catch(IOException e) {
// Ignore
}
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling Desktop.getDesktop().browse(uri) can throw HeadlessException / UnsupportedOperationException (e.g., on servers/CI or minimal JREs). Guard with Desktop.isDesktopSupported() and catch broader runtime failures so the login flow doesn't crash in headless environments.

Suggested change
try {
Desktop.getDesktop().browse(uri);
}
catch(IOException e) {
// Ignore
}
if(Desktop.isDesktopSupported()) {
try {
var desktop = Desktop.getDesktop();
if(desktop.isSupported(Desktop.Action.BROWSE)) {
desktop.browse(uri);
}
}
catch(IOException | RuntimeException e) {
// Ignore
}
}

Copilot uses AI. Check for mistakes.
Comment on lines 44 to 45
final ApiClient apiClient = new ApiClient();
apiClient.setBasePath(hubUrl);
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--hubUrl is no longer required (inherited from AbstractAuthorizationCode), but this command unconditionally uses hubUrl to build the API client base path. If the user supplies --accessToken without --hubUrl, this will fail at runtime. Consider making --hubUrl required for this command, or add an explicit validation with a clear error before calling the API.

Suggested change
final ApiClient apiClient = new ApiClient();
apiClient.setBasePath(hubUrl);
if (this.hubUrl == null || this.hubUrl.isBlank()) {
throw new CommandLine.ParameterException(
new CommandLine(this),
"Missing required option: '--hubUrl'. This command requires a hub URL to build the API client."
);
}
final ApiClient apiClient = new ApiClient();
apiClient.setBasePath(this.hubUrl);

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 7, 2026 20:22
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 46 to +52
public Void call() throws Exception {
final ApiClient apiClient = new ApiClient();
apiClient.setBasePath(hubUrl);
apiClient.addDefaultHeader("Authorization", "Bearer %s".formatted(this.login()));
this.call(new StorageProfileResourceApi(apiClient));
apiClient.setDebugging(debug);
final StorageProfileDto response = this.call(new StorageProfileResourceApi(apiClient));
System.out.println(new JSON().getContext(null).writeValueAsString(response));
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--hubUrl is now declared in AbstractAuthorizationCode with required = false, but this command always calls apiClient.setBasePath(hubUrl). If the user provides --accessToken (so login() succeeds) but omits --hubUrl, this will fail at runtime. Please make --hubUrl required for storage profile commands (or add an explicit validation in call() before using it).

Copilot uses AI. Check for mistakes.
Comment on lines 26 to 28
public class ArchiveStorageProfile extends AbstractAuthorizationCode implements Callable<Void> {
@CommandLine.Option(names = {"--hubUrl"}, description = "Hub URL. Example: \"https://hub.testing.katta.cloud\"", required = true)
String hubUrl;

@CommandLine.Option(names = {"--uuid"}, description = "The uuid.", required = true)
@CommandLine.Option(names = {"--uuid"}, description = "Storage Profile.", required = true)
String uuid;
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--hubUrl option was removed from this command, but the implementation still uses hubUrl (inherited from AbstractAuthorizationCode). Since --hubUrl is currently required = false in the superclass, it’s now possible to invoke storageprofile archive without providing a hub URL (especially when --accessToken is used), which will fail at runtime. Consider enforcing --hubUrl as required for this command (or validating it before apiClient.setBasePath(hubUrl)).

Copilot uses AI. Check for mistakes.
public void testCall() throws ApiException {
final StorageProfileResourceApi api = Mockito.mock(StorageProfileResourceApi.class);
final UUID vaultId = UUID.randomUUID();
final S3StaticStorageProfile cli = new S3StaticStorageProfile(vaultId.toString(), vaultId.toString(), "S3 static", "us-east-1", null,
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this unit test, the first constructor argument is hubUrl, but a random UUID string is passed instead. Even if it’s currently unused by call(api), it makes the test harder to understand and could break if the implementation starts relying on hubUrl. Prefer passing a realistic URL (or use the no-arg constructor and set fields explicitly).

Suggested change
final S3StaticStorageProfile cli = new S3StaticStorageProfile(vaultId.toString(), vaultId.toString(), "S3 static", "us-east-1", null,
final S3StaticStorageProfile cli = new S3StaticStorageProfile("https://hub.example.com", vaultId.toString(), "S3 static", "us-east-1", null,

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

4 participants