Skip to content

Conversation

sago2k8
Copy link
Contributor

@sago2k8 sago2k8 commented Sep 18, 2025

Implement Cli for reconciling redpanda roles based on controlplane roles

@Copilot Copilot AI review requested due to automatic review settings September 18, 2025 23:38
Copy link

@Copilot 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

Implements a new CLI/tooling layer to migrate/sync Redpanda Cloud roles (and their principals/ACLs) to dataplane (Core) clusters, plus supporting pagination, interceptors, and typed ACL/role utilities.

  • Adds generic pagination utilities and comprehensive tests.
  • Introduces Cloud and Dataplane API clients, migration logic (IdentityMigrator), and CLI with ACL configuration.
  • Provides retry/auth interceptors, CI workflow, and documentation (README, env example, ACL TOML).

Reviewed Changes

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

Show a summary per file
File Description
src/utils/pagination.ts Generic pagination helpers with accumulation strategies.
src/utils/pagination.test.ts Unit tests covering pagination behaviors.
src/types/index.ts Exposes core domain types and config interfaces.
src/types/acl-config.ts Strongly typed ACL configuration schema.
src/sync-role.ts Migration/sync orchestration of roles, principals, and ACL application.
src/sync-role.test.ts Tests for migrator cluster selection and basic migration paths.
src/interceptors.ts Auth and retry interceptors for ConnectRPC.
src/interceptors.test.ts Unit tests for interceptor behavior and combinations.
src/clients/dataplane-client.ts Dataplane client for roles, ACL creation, and membership sync.
src/clients/cloud-client.ts Cloud client for clusters, roles, bindings, users, SAs, with pagination usage.
src/cli.ts CLI command definitions, flag parsing, interactive prompts, ACL confirmation.
src/index.ts Library entrypoint exports.
package.json Project metadata, scripts, dependencies, build targets.
biome.json Linting/formatting configuration.
acls.toml ACL definition (currently only admin role).
README.md Comprehensive usage and operations documentation.
.github/workflows/ci.yml CI tasks for lint, test, build integrity.
.env.example Environment variable template.
.bunfig.toml / .npmrc Tooling and registry configuration.

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

async getRoleBindings(): Promise<RoleBinding[]> {
try {
return paginateToArray(
{ filter: { roleName: 'Admin' } },
(request) => this.roleBindingClient.listRoleBindings(request),
(response) => response.roleBindings,
{ requestName: 'Role bindings' }
);
Copy link
Preview

Copilot AI Sep 18, 2025

Choose a reason for hiding this comment

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

The method hard‑codes a filter for roleName 'Admin', so downstream logic (e.g., getRolesWithPrincipals expecting Admin, Writer, Reader) will never see bindings for Writer or Reader. Remove or parameterize this filter (or fetch unfiltered) so all target roles are discoverable.

Copilot uses AI. Check for mistakes.

src/sync-role.ts Outdated
Comment on lines 271 to 275
console.log('📋 Target roles for migration:');
const targetRoles = ['Admin', 'Writer', 'Reader'];
targetRoles.forEach((role) => {
console.log(` - ${role}`);
});
Copy link
Preview

Copilot AI Sep 18, 2025

Choose a reason for hiding this comment

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

[nitpick] The targetRoles array is only used for logging and not for filtering or validation; this can cause misleading output if upstream discovery fails to include some roles. Either enforce filtering based on this list or remove it to avoid implying those roles were considered in the actual migration loop.

Copilot uses AI. Check for mistakes.

Comment on lines +4 to +5
[roles.admin]
description = "Full administrative access to all cluster resources"
Copy link
Preview

Copilot AI Sep 18, 2025

Choose a reason for hiding this comment

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

Only the admin role is defined here, but the codebase (e.g., migration and discovery logic) references Writer and Reader roles; absence will trigger warnings and skip ACL creation for those roles. Either add writer/reader sections or adjust docs and logic to reflect that only admin ACLs are currently supported.

Copilot uses AI. Check for mistakes.

resource_name = "*"
resource_pattern_type = "LITERAL"
operation = "ALL"
permission_type = "ALLOW"
Copy link
Preview

Copilot AI Sep 18, 2025

Choose a reason for hiding this comment

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

Only the admin role is defined here, but the codebase (e.g., migration and discovery logic) references Writer and Reader roles; absence will trigger warnings and skip ACL creation for those roles. Either add writer/reader sections or adjust docs and logic to reflect that only admin ACLs are currently supported.

Suggested change
permission_type = "ALLOW"
permission_type = "ALLOW"
host = "*"
[roles.writer]
description = "Write access to topics and groups"
[[roles.writer.acls]]
resource_type = "TOPIC"
resource_name = "*"
resource_pattern_type = "LITERAL"
operation = "WRITE"
permission_type = "ALLOW"
host = "*"
[[roles.writer.acls]]
resource_type = "GROUP"
resource_name = "*"
resource_pattern_type = "LITERAL"
operation = "WRITE"
permission_type = "ALLOW"
host = "*"
[roles.reader]
description = "Read access to topics and groups"
[[roles.reader.acls]]
resource_type = "TOPIC"
resource_name = "*"
resource_pattern_type = "LITERAL"
operation = "READ"
permission_type = "ALLOW"
host = "*"
[[roles.reader.acls]]
resource_type = "GROUP"
resource_name = "*"
resource_pattern_type = "LITERAL"
operation = "READ"
permission_type = "ALLOW"

Copilot uses AI. Check for mistakes.

Comment on lines +60 to +71
messages.push(` 👤 Principal: RedpandaRole:__redpanda_cloud_role_${roleType}`);
messages.push(` 📊 Total ACL entries: ${roleConfig.acls.length}`);
Copy link
Preview

Copilot AI Sep 18, 2025

Choose a reason for hiding this comment

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

[nitpick] The principal displayed assumes the internal prefixed role name; ensure README and user guidance clarify this generated principal format, especially since the user supplies unprefixed role names (Admin/Writer/Reader). If mismatch is intentional, add a short clarification in the CLI help output.

Copilot uses AI. Check for mistakes.

console.log(`📤 Syncing membership for role: ${roleName}`);
console.log(' Target principals:', principals);
Copy link
Preview

Copilot AI Sep 18, 2025

Choose a reason for hiding this comment

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

Duplicate logging of 'Target principals:' (lines 133 and 146) adds noise; remove one occurrence.

Copilot uses AI. Check for mistakes.

);
const normalizedTargetMembers = new Set(principals);

console.log(' Target principals:', principals);
Copy link
Preview

Copilot AI Sep 18, 2025

Choose a reason for hiding this comment

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

Duplicate logging of 'Target principals:' (lines 133 and 146) adds noise; remove one occurrence.

Suggested change
console.log(' Target principals:', principals);

Copilot uses AI. Check for mistakes.

Comment on lines 5 to 8
"main": "src/index.ts",
"bin": {
"redpanda-migration": "./redpanda-migration"
},
Copy link
Preview

Copilot AI Sep 18, 2025

Choose a reason for hiding this comment

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

The declared bin path ./redpanda-migration does not correspond to any generated artifact (build scripts output unified-identity-toolkit* in out/*) and main points to TypeScript sources without a build pipeline for consumers. Provide a compiled JS entry (e.g., dist/index.js), align bin to an existing file (or add a wrapper script), or adjust build scripts to produce the declared binary name at project root.

Copilot uses AI. Check for mistakes.

package.json Outdated
Comment on lines 14 to 19
"build": "npm run build:linux",
"build:js": "bun build --target node --sourcemap --bundle --outdir dist src/cli.ts",
"build:linux": "mkdir -p out/linux && bun build --compile --minify --sourcemap --target bun-linux-x64 src/cli.ts --outfile out/linux/unified-identity-toolkit",
"build:macos": "mkdir -p out/macos && bun build --compile --minify --sourcemap --target bun-darwin-x64 src/cli.ts --outfile out/macos/unified-identity-toolkit",
"build:windows": "mkdir -p out/windows && bun build --compile --minify --sourcemap --target bun-windows-x64 src/cli.ts --outfile out/windows/unified-identity-toolkit.exe",
"build:all": "npm run build:linux && npm run build:macos && npm run build:windows",
Copy link
Preview

Copilot AI Sep 18, 2025

Choose a reason for hiding this comment

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

The declared bin path ./redpanda-migration does not correspond to any generated artifact (build scripts output unified-identity-toolkit* in out/*) and main points to TypeScript sources without a build pipeline for consumers. Provide a compiled JS entry (e.g., dist/index.js), align bin to an existing file (or add a wrapper script), or adjust build scripts to produce the declared binary name at project root.

Suggested change
"build": "npm run build:linux",
"build:js": "bun build --target node --sourcemap --bundle --outdir dist src/cli.ts",
"build:linux": "mkdir -p out/linux && bun build --compile --minify --sourcemap --target bun-linux-x64 src/cli.ts --outfile out/linux/unified-identity-toolkit",
"build:macos": "mkdir -p out/macos && bun build --compile --minify --sourcemap --target bun-darwin-x64 src/cli.ts --outfile out/macos/unified-identity-toolkit",
"build:windows": "mkdir -p out/windows && bun build --compile --minify --sourcemap --target bun-windows-x64 src/cli.ts --outfile out/windows/unified-identity-toolkit.exe",
"build:all": "npm run build:linux && npm run build:macos && npm run build:windows",
"build": "npm run build:linux && npm run build:bin",
"build:js": "bun build --target node --sourcemap --bundle --outdir dist src/cli.ts",
"build:linux": "mkdir -p out/linux && bun build --compile --minify --sourcemap --target bun-linux-x64 src/cli.ts --outfile out/linux/unified-identity-toolkit",
"build:macos": "mkdir -p out/macos && bun build --compile --minify --sourcemap --target bun-darwin-x64 src/cli.ts --outfile out/macos/unified-identity-toolkit",
"build:windows": "mkdir -p out/windows && bun build --compile --minify --sourcemap --target bun-windows-x64 src/cli.ts --outfile out/windows/unified-identity-toolkit.exe",
"build:all": "npm run build:linux && npm run build:macos && npm run build:windows",
"build:bin": "cp out/linux/unified-identity-toolkit ./redpanda-migration",

Copilot uses AI. Check for mistakes.

README.md Outdated
Comment on lines 66 to 72
- **Linux**: `redpanda-toolkit-linux`
- **macOS**: `redpanda-toolkit-macos`
- **Windows**: `redpanda-toolkit-windows.exe`

Make the binary executable (Linux/macOS):
```bash
chmod +x redpanda-toolkit-linux
Copy link
Preview

Copilot AI Sep 18, 2025

Choose a reason for hiding this comment

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

Binary names here do not match build outputs (unified-identity-toolkit* in package.json scripts) or the declared npm bin (redpanda-migration). Update the README or rename build artifacts for consistency to prevent user confusion.

Suggested change
- **Linux**: `redpanda-toolkit-linux`
- **macOS**: `redpanda-toolkit-macos`
- **Windows**: `redpanda-toolkit-windows.exe`
Make the binary executable (Linux/macOS):
```bash
chmod +x redpanda-toolkit-linux
- **Linux**: `unified-identity-toolkit-linux`
- **macOS**: `unified-identity-toolkit-macos`
- **Windows**: `unified-identity-toolkit-windows.exe`
Make the binary executable (Linux/macOS):
```bash
chmod +x unified-identity-toolkit-linux

Copilot uses AI. Check for mistakes.

@sago2k8 sago2k8 force-pushed the UX-457/sj/impersonation-role-sync-script branch 8 times, most recently from 24d1607 to 8552ca2 Compare September 19, 2025 09:39

steps:
- name: Checkout code
uses: actions/checkout@v4

Choose a reason for hiding this comment

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

We can also use @v5. it was released 2 months ago

@sago2k8 sago2k8 force-pushed the UX-457/sj/impersonation-role-sync-script branch 2 times, most recently from f0b1267 to 59a5175 Compare September 19, 2025 09:50
.npmrc Outdated
Comment on lines 13 to 14
# Enable package-lock generation
package-lock=true No newline at end of file

Choose a reason for hiding this comment

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

Do we need this? We use yarn.lock already it seems, I think this setting is for package-lock.json specifically.

"check": "biome check .",
"check:fix": "biome check --write .",
"type-check": "tsc --noEmit",
"clean": "rm -rf dist out"

Choose a reason for hiding this comment

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

If we need to support different arch, we can consider using rimraf

package.json Outdated
"node": ">=18.0.0"
},
"scripts": {
"build": "npm run build:linux",

Choose a reason for hiding this comment

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

Maybe use bun everywhere instead of npm?

Choose a reason for hiding this comment

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

I think in subsequent PRs we could consider moving this to inkjs (React for CLIs)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah I thought about it, but today, it's very simple.

* Unit tests for ConnectRPC interceptors
*/

import { beforeEach, describe, expect, jest, test } from 'bun:test';

Choose a reason for hiding this comment

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

Really cool you could manage to get bun:test working, it improved a lot recently.

@@ -0,0 +1,13 @@
# Redpanda Cloud API Token (required)
# Get this bearer token from your Redpanda Cloud organization settings
REDPANDA_CLOUD_API_TOKEN=your-cloud-api-bearer-token-here
Copy link

Choose a reason for hiding this comment

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

It would be useful if you could set up a service account credentials, since tokens expire

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tought about it bt wanted to keep it small and simple initially

Copy link

Choose a reason for hiding this comment

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

are we versioning this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, it will be semver with tags, for next PR

/**
* Convenience function for paginating into an array
*/
export async function paginateToArray<
Copy link

Choose a reason for hiding this comment

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

Weird name, ListAllPages maybe?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

you can also paginate to Map hehe

let pageCount = 0;
let totalResults = 0;

do {
Copy link

Choose a reason for hiding this comment

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

This got to be the frist time I see a do implemented in ts

Choose a reason for hiding this comment

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

x2

Comment on lines +17 to +18
"build:macos": "mkdir -p out/macos && bun build --compile --minify --sourcemap --target bun-darwin-x64 src/cli.ts --outfile out/macos/unified-identity-toolkit",
"build:windows": "mkdir -p out/windows && bun build --compile --minify --sourcemap --target bun-windows-x64 src/cli.ts --outfile out/windows/unified-identity-toolkit.exe",

Choose a reason for hiding this comment

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

do you need this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe windows is not important, but I want to have completeness, what's the concern?

let pageCount = 0;
let totalResults = 0;

do {

Choose a reason for hiding this comment

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

x2

Comment on lines +122 to +135
{
name: 'Admin - Full administrative access to cluster',
value: 'Admin',
},

Choose a reason for hiding this comment

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

don't you need the reader and writer options here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Initially I want to focus only on the Admin Role, but eventually yes .

Copy link

@andresaristizabal andresaristizabal left a comment

Choose a reason for hiding this comment

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

LGTM

Basic bun setup with ci and bun well known configurations

Signed-off-by: santiago <[email protected]>
@sago2k8 sago2k8 force-pushed the UX-457/sj/impersonation-role-sync-script branch from 59a5175 to 617d200 Compare September 22, 2025 09:24
Install bun dependencies, make sure all necessary deps are installed

Signed-off-by: santiago <[email protected]>
@sago2k8 sago2k8 force-pushed the UX-457/sj/impersonation-role-sync-script branch from 617d200 to e3ec89c Compare September 22, 2025 11:41
implement simple sync cli for redpada roles

Signed-off-by: santiago <[email protected]>
Basic testing for the cli

Signed-off-by: santiago <[email protected]>
Signed-off-by: santiago <[email protected]>
Implement JS bundle so the execution of the cli is very simple

Signed-off-by: santiago <[email protected]>
@sago2k8 sago2k8 force-pushed the UX-457/sj/impersonation-role-sync-script branch from e3ec89c to bafeccd Compare September 22, 2025 13:13
@sago2k8 sago2k8 merged commit 10cec64 into main Sep 22, 2025
3 checks passed
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.

4 participants