Skip to content

feat(cli): Unsafe update key cli#3733

Draft
c-r33d wants to merge 11 commits into
mainfrom
unsafe-update-key-cli
Draft

feat(cli): Unsafe update key cli#3733
c-r33d wants to merge 11 commits into
mainfrom
unsafe-update-key-cli

Conversation

@c-r33d

@c-r33d c-r33d commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds CLI support for unsafely updating KAS registry keys through the new UnsafeUpdateKey service RPC.

This introduces:

  • otdfctl policy kas-registry key unsafe update
  • support for changing eligible keys between remote and public_key
  • support for updating the provider config on an existing remote key
  • unsafe confirmation behavior consistent with other destructive/unsafe key commands
  • CLI docs and examples for the new command
  • E2E BATS coverage for successful updates and service-originated validation errors

CLI Behavior

The new command accepts:

  • --id: system key ID to update
  • --mode: target key mode, limited client-side to remote or public_key
  • --provider-config-id: provider config ID for remote mode or remote provider config updates
  • --force: bypasses interactive unsafe confirmation

Request validation for provider config combinations is intentionally handled by the service. The CLI now validates only CLI-level concerns like required
flags, UUID parsing, and unsupported mode strings.

Testing

Updated otdfctl/e2e/kas-keys.bats to cover:

  • remote to public key mode
  • public key to remote mode
  • remote provider config-only update
  • invalid provider config UUID
  • missing ID
  • service errors for missing provider config
  • service errors for provider config not allowed
  • service errors for unsupported existing key mode

Depends On

@github-actions github-actions Bot added comp:db DB component comp:policy Policy Configuration ( attributes, subject mappings, resource mappings, kas registry) comp:sdk A software development kit, including library, for client applications and inter-service communicati docs Documentation labels Jul 8, 2026
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: d41bd31a-71ea-43c2-926c-f21179e01b9d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch unsafe-update-key-cli

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the size/l label Jul 8, 2026
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 223.681781ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 114.676486ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 426.003384ms
Throughput 234.74 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 46.392952672s
Average Latency 462.464573ms
Throughput 107.77 requests/second

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request adds support for unsafely updating KAS registry keys via a new CLI command and service RPC. It enables changing key modes between 'remote' and 'public_key' and updating provider configurations for existing remote keys, while ensuring necessary safety checks and validation are in place.

Highlights

  • New CLI Command: Added otdfctl policy kas-registry key unsafe update to support modifying KAS registry keys.
  • Service RPC: Introduced UnsafeUpdateKey RPC to allow switching key modes and updating provider configurations.
  • Validation and Safety: Implemented strict validation for key modes and provider configurations, including interactive confirmation for unsafe operations.
  • Testing: Expanded E2E BATS coverage and added unit tests for the new update functionality and error handling.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Ignored Files
  • Ignored by pattern: docs/openapi/**/* (1)
    • docs/openapi/policy/unsafe/unsafe.openapi.yaml
  • Ignored by pattern: protocol/**/* (3)
    • protocol/go/policy/unsafe/unsafe.pb.go
    • protocol/go/policy/unsafe/unsafe_grpc.pb.go
    • protocol/go/policy/unsafe/unsafeconnect/unsafe.connect.go
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.


The keys were set in stone and cold, But now a change is brave and bold. With unsafe flags and careful hand, We update keys across the land.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces an unsafe key update feature (UnsafeUpdateKey) allowing administrators to switch key modes between REMOTE and PUBLIC_KEY_ONLY or update the provider configuration for existing remote keys. The changes span Protobuf definitions, database queries, service-layer logic, CLI commands, and comprehensive tests. The review feedback suggests several defensive programming enhancements to prevent potential nil pointer dereferences when handling key objects and responses, as well as adding a default case to a key mode switch statement to ensure robust validation.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +557 to +559
if existing.GetKey() == nil {
return nil, errors.New("existing key is nil")
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Defensive programming: existing could be nil. Checking both existing and existing.GetKey() for nil prevents a potential nil pointer dereference panic in the service layer.

Suggested change
if existing.GetKey() == nil {
return nil, errors.New("existing key is nil")
}
if existing == nil || existing.GetKey() == nil {
return nil, errors.New("existing key is nil")
}

Comment on lines +611 to +631
switch r.GetKeyMode() {
case policy.KeyMode_KEY_MODE_REMOTE:
if !newProviderConfiguration.Valid {
return params, db.ErrUnsafeUpdateKeyProviderConfigRequired
}
params.KeyMode = newKeyMode
params.ProviderConfigID = newProviderConfiguration
case policy.KeyMode_KEY_MODE_PUBLIC_KEY_ONLY:
if r.GetProviderConfigId() != "" {
return params, db.ErrUnsafeUpdateKeyProviderConfigNotAllowed
}
params.KeyMode = newKeyMode
case policy.KeyMode_KEY_MODE_UNSPECIFIED:
if existingMode != policy.KeyMode_KEY_MODE_REMOTE {
return params, db.ErrUnsafeUpdateKeyProviderConfigExistingMode
}
if !newProviderConfiguration.Valid {
return params, db.ErrUnsafeUpdateKeyProviderConfigRequired
}
params.ProviderConfigID = newProviderConfiguration
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The switch statement on r.GetKeyMode() does not have a default case. If an unsupported key mode is passed, it will fall through and return params, nil without validation, which could lead to unexpected database updates. Adding a default case to return db.ErrEnumValueInvalid ensures robust validation.

	switch r.GetKeyMode() {
	case policy.KeyMode_KEY_MODE_REMOTE:
		if !newProviderConfiguration.Valid {
			return params, db.ErrUnsafeUpdateKeyProviderConfigRequired
		}
		params.KeyMode = newKeyMode
		params.ProviderConfigID = newProviderConfiguration
	case policy.KeyMode_KEY_MODE_PUBLIC_KEY_ONLY:
		if r.GetProviderConfigId() != "" {
			return params, db.ErrUnsafeUpdateKeyProviderConfigNotAllowed
		}
		params.KeyMode = newKeyMode
	case policy.KeyMode_KEY_MODE_UNSPECIFIED:
		if existingMode != policy.KeyMode_KEY_MODE_REMOTE {
			return params, db.ErrUnsafeUpdateKeyProviderConfigExistingMode
		}
		if !newProviderConfiguration.Valid {
			return params, db.ErrUnsafeUpdateKeyProviderConfigRequired
		}
		params.ProviderConfigID = newProviderConfiguration
	default:
		return params, db.ErrEnumValueInvalid
	}

Comment on lines +454 to +456
if kasKey.GetKey() == nil {
return nil
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Defensive programming: kasKey could be nil. Checking both kasKey and kasKey.GetKey() for nil prevents a potential nil pointer dereference panic during audit logging.

Suggested change
if kasKey.GetKey() == nil {
return nil
}
if kasKey == nil || kasKey.GetKey() == nil {
return nil
}

cli.ExitWithError("Failed to get kas key", err)
}

existingKey := existingKasKey.GetKey()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Defensive programming: existingKasKey or existingKasKey.GetKey() could be nil. Checking for nil before calling GetKey() prevents a potential nil pointer dereference panic.

	if existingKasKey == nil || existingKasKey.GetKey() == nil {
		cli.ExitWithError("Failed to get kas key", fmt.Errorf("key details are missing"))
	}
	existingKey := existingKasKey.GetKey()

return nil, err
}

return resp.GetKey(), nil

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Defensive programming: resp could be nil if the underlying SDK call returns a nil response without an error (e.g., in mock/test environments or certain client configurations). Checking for nil prevents a nil pointer dereference panic when calling resp.GetKey().

	if resp == nil {
		return nil, fmt.Errorf("received empty response from unsafe update key service")
	}
	return resp.GetKey(), nil

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 214.518208ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 113.29158ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 427.194209ms
Throughput 234.09 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 45.77429927s
Average Latency 455.679059ms
Throughput 109.23 requests/second

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

⚠️ Govulncheck found vulnerabilities ⚠️

The following modules have known vulnerabilities:

  • examples
  • otdfctl
  • sdk
  • service
  • lib/fixtures
  • tests-bdd

See the workflow run for details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp:db DB component comp:policy Policy Configuration ( attributes, subject mappings, resource mappings, kas registry) comp:sdk A software development kit, including library, for client applications and inter-service communicati docs Documentation size/l

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant