Skip to content

♻️ Split PermissionStrategy into ModeStrategy + OwnerStrategy#2593

Merged
ChanTsune merged 1 commit into
mainfrom
cli/core/refactoring
Jan 11, 2026
Merged

♻️ Split PermissionStrategy into ModeStrategy + OwnerStrategy#2593
ChanTsune merged 1 commit into
mainfrom
cli/core/refactoring

Conversation

@ChanTsune
Copy link
Copy Markdown
Owner

@ChanTsune ChanTsune commented Jan 10, 2026

This refactoring separates mode handling from owner handling internally, enabling the fine-grained control required for bsdtar-style -p flag semantics (which affects mode but not owner).

Changes:

  • Create new types: ModeStrategy, OwnerStrategy, OwnerOptions
  • Update KeepOptions to use split strategies instead of combined
  • Update PermissionStrategyResolver to return (ModeStrategy, OwnerStrategy)
  • Update apply_metadata in core.rs for new strategy types
  • Update restore_permissions in extract.rs for new strategy types
  • Update all KeepOptions construction sites in create, extract, append, update, and stdio commands
  • Remove legacy PermissionStrategy and OwnerSource types

No user-facing changes in this refactoring phase.

Summary by CodeRabbit

  • Refactor
    • Split permission handling into separate mode and owner strategies, improving how file mode and ownership are determined and applied.
    • Ownership and mode restoration are now handled independently, with clearer behavior across create/extract/update and platform-specific warnings when features are unsupported.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 10, 2026

📝 Walkthrough

Walkthrough

This change splits the previous monolithic PermissionStrategy into two distinct strategies: ModeStrategy (file mode handling) and OwnerStrategy (ownership handling). OwnerSource is replaced by OwnerOptions, resolver.resolve() now returns (ModeStrategy, OwnerStrategy), and call sites/metadata paths are updated to use the split strategies.

Changes

Cohort / File(s) Summary
Permission types
cli/src/command/core/permission.rs
Replaced OwnerSource with OwnerOptions; removed PermissionStrategy; added ModeStrategy and OwnerStrategy enums (with defaults and derives).
Core API & metadata plumbing
cli/src/command/core.rs
Re-exported ModeStrategy, OwnerOptions, OwnerStrategy; KeepOptions now holds mode_strategy and owner_strategy instead of a single permission strategy; PermissionStrategyResolver::resolve() now returns (ModeStrategy, OwnerStrategy); apply_metadata paths updated for Unix/Windows/macOS.
Commands wiring (create/append/update/stdio)
cli/src/command/create.rs, cli/src/command/append.rs, cli/src/command/update.rs, cli/src/command/stdio.rs
Introduced two-step resolution: compute (mode_strategy, owner_strategy) via resolver and pass both into KeepOptions (same_owner handling adjusted where applicable).
Extract & ownership restore
cli/src/command/extract.rs
KeepOptions uses split strategies; restore_permissions replaced by restore_owner/restore_mode with OwnerOptions/OwnerStrategy driving ownership and mode restoration; platform-gated behavior updated and warnings added for unsupported platforms.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A hop, a split — two paths now gleam,
Mode and Owner chase a shared dream,
OwnerOptions tucked in neat and bright,
Resolver pairs guide day and night,
I nibble code and cheer the new light.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main refactoring change: splitting a monolithic PermissionStrategy into two separate strategies (ModeStrategy and OwnerStrategy).
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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 and usage tips.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @ChanTsune, 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 implements a significant internal refactoring of how file permissions are managed within the application. By splitting the monolithic PermissionStrategy into distinct ModeStrategy and OwnerStrategy components, the codebase gains enhanced flexibility and fine-grained control over permission attributes. This change is foundational for future features, such as supporting bsdtar-style -p flag semantics, which require independent manipulation of file modes and ownership. Crucially, this refactoring introduces no user-facing changes in the current phase, focusing purely on improving the internal architecture.

Highlights

  • New Type Definitions: Introduced new types: ModeStrategy, OwnerStrategy, and OwnerOptions to provide a more granular representation of permission handling.
  • Refactored KeepOptions: The KeepOptions struct has been updated to utilize the newly separated ModeStrategy and OwnerStrategy instead of a single PermissionStrategy.
  • Permission Strategy Resolution: The PermissionStrategyResolver now resolves CLI options into a tuple of (ModeStrategy, OwnerStrategy), allowing independent control over file mode and ownership.
  • Metadata Application Logic: The apply_metadata function in core.rs and restore_permissions in extract.rs have been updated to correctly interpret and apply the new ModeStrategy and OwnerStrategy types.
  • Command-line Option Integration: All command-line interface (CLI) commands that construct KeepOptions (create, extract, append, update, stdio) have been modified to use the new split permission strategies.
  • Legacy Type Removal: The deprecated PermissionStrategy and OwnerSource types have been removed, streamlining the permission handling architecture.
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 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 counter productive. 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.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

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.

Copy link
Copy Markdown
Contributor

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

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 is a great refactoring that splits the monolithic PermissionStrategy into more granular ModeStrategy and OwnerStrategy. This significantly improves the clarity and flexibility of permission handling. However, I've identified a critical issue in the extraction logic where file modes are not restored if owner preservation is disabled, which undermines the goal of this refactoring. I've provided suggestions to correct this behavior. Additionally, I've included a couple of medium-severity suggestions for improving code clarity and documentation.

Comment thread cli/src/command/extract.rs
Comment thread cli/src/command/extract.rs Outdated
Comment thread cli/src/command/extract.rs
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @cli/src/command/extract.rs:
- Around line 10-15: restore_metadata() currently only applies permissions when
OwnerStrategy::Preserve and restore_permissions() always does both chown+chmod;
change the logic to split chown and chmod so chmod is controlled by
keep_options.mode_strategy (e.g., ModeStrategy::Preserve) independent of owner
handling. Update restore_metadata() to consult keep_options.mode_strategy for
applying file mode, and refactor restore_permissions() (or the helper that calls
chown/chmod) to call chown only when owner_strategy dictates but call chmod when
mode_strategy dictates; reference ModeStrategy, keep_options.mode_strategy,
OwnerStrategy::Preserve, restore_metadata(), and restore_permissions() when
making the changes.
🧹 Nitpick comments (4)
cli/src/command/core/permission.rs (1)

1-30: Good split + sensible defaults; consider clarifying “empty string” semantics for uname/gname.

OwnerOptions/ModeStrategy/OwnerStrategy look consistent and the Never defaults are appropriate. One small thing: elsewhere numeric_owner appears to be represented by Some(String::new()) for names; it’s worth documenting here that Some("") is an intentional sentinel distinct from None.

cli/src/command/append.rs (1)

375-405: LGTM: strategy resolution is now explicit and reused.

This makes the KeepOptions construction clearer and aligns with the new split model.

cli/src/command/stdio.rs (1)

653-679: Consistent adoption of (mode_strategy, owner_strategy) across stdio modes; consider a tiny helper to DRY this up.

The repeated PermissionStrategyResolver { ... }.resolve() blocks are identical in shape; a private helper (or builder) could reduce copy/paste and keep future flag additions safer.

Also applies to: 746-785, 917-950, 1045-1078

cli/src/command/core.rs (1)

712-780: Consider making apply_metadata() explicitly consult keep_options.mode_strategy (even if currently redundant).

Right now, permission emission is gated by OwnerStrategy::Preserve { .. }. If later you allow ModeStrategy::Preserve with OwnerStrategy::Never (the motivating split), this function will silently stop storing mode bits. A small match keep_options.mode_strategy { Preserve => { ... }, Never => {} } (and optionally debug_assert!(!matches!(owner_strategy, Preserve) || matches!(mode_strategy, Preserve))) would make the invariant explicit.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9e79faa and 129b0b5.

📒 Files selected for processing (7)
  • cli/src/command/append.rs
  • cli/src/command/core.rs
  • cli/src/command/core/permission.rs
  • cli/src/command/create.rs
  • cli/src/command/extract.rs
  • cli/src/command/stdio.rs
  • cli/src/command/update.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (17)
  • GitHub Check: Test WebAssembly (beta, wasm32-unknown-emscripten)
  • GitHub Check: tier1 (windows-11-arm, nightly)
  • GitHub Check: tier1 (macos-latest, stable)
  • GitHub Check: plan
  • GitHub Check: tier1 (windows-11-arm, beta)
  • GitHub Check: tier1 (windows-latest, beta)
  • GitHub Check: tier1 (windows-latest, nightly)
  • GitHub Check: tier1 (ubuntu-latest, nightly)
  • GitHub Check: tier1 (windows-11-arm, stable)
  • GitHub Check: tier1 (ubuntu-latest, beta)
  • GitHub Check: tier1 (ubuntu-latest, stable)
  • GitHub Check: tier1 (ubuntu-22.04-arm, beta)
  • GitHub Check: tier1 (ubuntu-22.04-arm, stable)
  • GitHub Check: msrv (ubuntu-latest, portable-network-archive)
  • GitHub Check: Test WebAssembly (stable, wasm32-wasip2)
  • GitHub Check: Test WebAssembly (stable, wasm32-unknown-emscripten)
  • GitHub Check: Test WebAssembly (stable, wasm32-unknown-unknown)
🔇 Additional comments (3)
cli/src/command/update.rs (1)

384-414: LGTM: consistent split-strategy wiring with append/create.

cli/src/command/create.rs (1)

462-492: LGTM: create path correctly threads split strategies into KeepOptions.

cli/src/command/core.rs (1)

11-11: Nice cleanup: KeepOptions + resolver now match the split model.

Also applies to: 199-208, 259-316

Comment thread cli/src/command/extract.rs
@github-actions github-actions Bot added the cli This issue is about cli application label Jan 10, 2026
This refactoring separates mode handling from owner handling internally,
enabling the fine-grained control required for bsdtar-style `-p` flag
semantics (which affects mode but not owner).

Changes:
- Create new types: ModeStrategy, OwnerStrategy, OwnerOptions
- Update KeepOptions to use split strategies instead of combined
- Update PermissionStrategyResolver to return (ModeStrategy, OwnerStrategy)
- Update apply_metadata in core.rs for new strategy types
- Update restore_permissions in extract.rs for new strategy types
- Update all KeepOptions construction sites in create, extract, append,
  update, and stdio commands
- Remove legacy PermissionStrategy and OwnerSource types

No user-facing changes in this refactoring phase.
@ChanTsune ChanTsune force-pushed the cli/core/refactoring branch from 129b0b5 to 5fb7fc8 Compare January 10, 2026 11:30
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @cli/src/command/stdio.rs:
- Around line 653-663: The extraction logic ignores the --same-owner flag
because PermissionStrategyResolver is constructed with same_owner hardcoded to
true; change the argument definition to set default_value_t = true for the
same_owner clap Arg and construct the resolver with same_owner: args.same_owner
&& !args.no_same_owner so PermissionStrategyResolver { ..., same_owner, uname,
gname, uid, gid, numeric_owner: args.numeric_owner }.call resolve(); update both
occurrences mentioned (around the current call and the one at lines ~744-757) so
--same-owner and --no-same-owner behave correctly.
🧹 Nitpick comments (4)
cli/src/command/core/permission.rs (1)

1-10: Clarify OwnerOptions semantics for Some("") (numeric-owner sentinel).

OwnerOptions docs describe None meaning “use filesystem/archive”, but other code paths appear to use Some(String::new()) to force “no name”. Please document that explicitly here (or encode it as a dedicated enum/flag) to avoid accidental semantic drift later.

Proposed doc tweak
 /// Override values for ownership during permission operations.
 /// During creation: Override values stored in archive (None = use filesystem)
 /// During extraction: Override values restored from archive (None = use archive)
+///
+/// Note: Some call sites may use `Some("")` as a sentinel meaning "do not store/use names"
+/// (numeric-owner behavior). Prefer an explicit enum/flag if this grows further.

Also applies to: 22-30

cli/src/command/stdio.rs (1)

651-686: Resolver wiring to (mode_strategy, owner_strategy) is clean; consider deduplicating boilerplate.

The repeated PermissionStrategyResolver { ... }.resolve() blocks across create/extract/append/update in this file are nearly identical; a small helper (e.g., fn resolve_strategies(...)) would reduce future drift.

Also applies to: 917-951, 1045-1078

cli/src/command/core.rs (2)

199-208: Resolver split is solid; consider making numeric-owner intent explicit (avoid Some("")).

Also applies to: 259-316


711-781: apply_metadata is currently gated by OwnerStrategy (ModeStrategy unused here).

If the long-term goal is “preserve mode but not owner”, you’ll likely want apply_metadata to emit permission metadata when mode_strategy == Preserve even if owner_strategy == Never (with clearly-defined placeholder owner fields). If that’s intentionally deferred, a short comment would help prevent future confusion.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 129b0b5 and 5fb7fc8.

📒 Files selected for processing (7)
  • cli/src/command/append.rs
  • cli/src/command/core.rs
  • cli/src/command/core/permission.rs
  • cli/src/command/create.rs
  • cli/src/command/extract.rs
  • cli/src/command/stdio.rs
  • cli/src/command/update.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • cli/src/command/update.rs
  • cli/src/command/append.rs
🧰 Additional context used
🧬 Code graph analysis (1)
cli/src/command/extract.rs (3)
cli/src/utils/fs.rs (2)
  • lchown (49-67)
  • chmod (70-80)
cli/src/utils/os/windows/fs.rs (4)
  • lchown (25-36)
  • lchown (68-68)
  • lchown (69-69)
  • chmod (39-47)
cli/src/utils/os/unix/fs.rs (1)
  • chmod (10-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: tier1 (windows-latest, beta)
  • GitHub Check: tier1 (macos-latest, nightly)
  • GitHub Check: rust_check_doc
  • GitHub Check: tier1 (macos-latest, nightly)
  • GitHub Check: tier1 (ubuntu-22.04-arm, beta)
  • GitHub Check: tier1 (macos-latest, stable)
  • GitHub Check: Test WebAssembly (beta, wasm32-wasip1)
  • GitHub Check: Test WebAssembly (beta, wasm32-wasip2)
  • GitHub Check: tier1 (ubuntu-22.04-arm, stable)
  • GitHub Check: Test WebAssembly (nightly-2025-12-09, wasm32-wasip1)
  • GitHub Check: tier1 (windows-latest, beta)
  • GitHub Check: tier1 (macos-latest, beta)
  • GitHub Check: Test WebAssembly (stable, wasm32-unknown-unknown)
  • GitHub Check: tier1 (ubuntu-latest, stable)
  • GitHub Check: tier1 (ubuntu-22.04-arm, nightly)
  • GitHub Check: Test WebAssembly (beta, wasm32-unknown-emscripten)
  • GitHub Check: Test WebAssembly (stable, wasm32-unknown-emscripten)
  • GitHub Check: msrv (ubuntu-latest, libpna)
  • GitHub Check: msrv (ubuntu-latest, pna)
  • GitHub Check: tier3_cross (redoxos/redoxer, x86_64-unknown-redox)
🔇 Additional comments (3)
cli/src/command/create.rs (1)

462-492: LGTM: creation now stores split strategies in KeepOptions consistently.

cli/src/command/extract.rs (2)

873-895: Good: owner restored before mode (avoids setuid/setgid clobbering).


1052-1094: The utils::fs::chmod function is correctly available and configured for Windows builds. Both Windows (using libc::wchmod) and Unix implementations exist in cli/src/utils/os/{windows,unix}/fs.rs and are properly isolated with matching #[cfg(windows)] and #[cfg(unix)] attributes. The wrapper function in cli/src/utils/fs.rs:70 is gated with #[cfg(any(windows, unix))], and the usage in restore_mode matches this cfg attribute. No issues found.

Comment thread cli/src/command/stdio.rs
@ChanTsune ChanTsune merged commit f2f0336 into main Jan 11, 2026
100 checks passed
@ChanTsune ChanTsune deleted the cli/core/refactoring branch January 11, 2026 13:59
@coderabbitai coderabbitai Bot mentioned this pull request Jan 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli This issue is about cli application

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant