Skip to content

Conversation

@matts1
Copy link
Contributor

@matts1 matts1 commented Dec 5, 2025

See docs/design/secure-config.md for many more details.

Fixes #3303
Fixes #1595

Checklist

If applicable:

  • I have updated CHANGELOG.md
  • I have updated the documentation (README.md, docs/, demos/)
  • I have updated the config schema (cli/src/config-schema.json)
  • I have added/updated tests to cover my changes

@matts1 matts1 requested a review from a team as a code owner December 5, 2025 01:39
@matts1 matts1 requested a review from yuja December 5, 2025 01:39
@matts1 matts1 force-pushed the push-utlknmrzwpmm branch 3 times, most recently from eb79eda to 721cf57 Compare December 5, 2025 02:24
@matts1
Copy link
Contributor Author

matts1 commented Dec 5, 2025

I've added Yuja as a reviewer since he's the one I strictly need approval from, but FYI @martinvonz and @PhilipMetzger in case you'd like to review as well.

@higgsd
Copy link
Contributor

higgsd commented Dec 5, 2025

Some thoughts on the design doc:

  • Missing noun: The attacker can now see [???] stored in the repository
  • Content - explain more explicitly how the victim's signatures are misused (or if that's just A Bad Thing)
  • Does anything problematic happen if the user's .config directory is itself a jj repo?
    • Is there a need to prevent a repo from storing its configs inside itself?
  • Perhaps give users a preferred way to copy/restore a config, so they don't have to hand-correlate repos with config-ids
    • Maybe provide jj config replace [scope] [PATH | --stdin] to help?
  • Perhaps provide a way to list known config-ids and the disposition of their repos/workspaces
    • Its an intermediate step (or alternative) to jj config gc, for review and manual cleanup

@matts1 matts1 force-pushed the push-utlknmrzwpmm branch from 721cf57 to 02513f6 Compare December 5, 2025 04:33
@matts1
Copy link
Contributor Author

matts1 commented Dec 5, 2025

  • Missing noun: The attacker can now see [???] stored in the repository
  • Content - explain more explicitly how the victim's signatures are misused (or if that's just A Bad Thing)

This was a remnant of the old proposal. I've renamed it to "config / config signatures"

  • Does anything problematic happen if the user's .config directory is itself a jj repo?

Not really

  • Is there a need to prevent a repo from storing its configs inside itself?

Yes, this is explained in the design doc in attack vector 1. Other attack vectors just build on top of this.

  • Perhaps give users a preferred way to copy/restore a config, so they don't have to hand-correlate repos with config-ids
    • Maybe provide jj config replace [scope] [PATH | --stdin] to help?

This feature is supposed to be transparent to the user. The user does not have to hand-correlate repos with config IDs. It should happen for them automatically. If you did want to manually do it, it's as simple as writing the config id to .jj/repo-config-id, or just running jj config edit and copying the config from there.

  • Perhaps provide a way to list known config-ids and the disposition of their repos/workspaces
    • Its an intermediate step (or alternative) to jj config gc, for review and manual cleanup

If someone wanted to implemented it, I wouldn't stop them, but I already mentioned in the design doc that GC was out of scope of the initial version, but that we might consider later.

Copy link
Contributor

@PhilipMetzger PhilipMetzger left a comment

Choose a reason for hiding this comment

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

minor stuff, I think you also have missed implementing the deprecation warning.

Comment on lines +227 to +245
#[cfg(unix)]
{
// Make old versions and new versions of jj share the same config file.
std::fs::remove_file(&legacy_config).context(&legacy_config)?;
std::os::unix::fs::symlink(dunce::canonicalize(&config_file)?, &legacy_config)
.context(&legacy_config)?;
}
#[cfg(not(unix))]
{
// I considered making this readonly, but that would prevent you from
// updating the config with old versions of jj.
// In the future, we consider something a little more robust, where as
// the non-legacy config changes, we propagate that to the legacy config.
// However, it seems a little overkill, considering it only affects windows
// users who use multiple versions of jj at once, and only for a year.
let mut content = CONTENT_PREFIX.as_bytes().to_vec();
content.extend_from_slice(&config);
std::fs::write(&legacy_config, content).context(&legacy_config)?;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: create a helper for this, this is also missing a deprecation warning with the year long migration timeline.

content: &[u8],
metadata: &ConfigMetadata,
) -> Result<PathBuf, SecureConfigError> {
let d = self.config_dir.join(config_id);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: d could be repo_dir since single char variables make for bad readabilty.

// We don't use JJRng because that depends on the seed, which comes
// from config files, so doing so would be circular.
rng: RefCell<ChaCha20Rng>,

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: delete spurious newline here

std::fs::create_dir_all(&d).context(&d)?;
self.update_metadata(&d, metadata)?;
if !content.is_empty() {
std::fs::write(&config_path, content).context(&config_path)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: import atleast std so its just fs::write(...) since this code isn't async where it otherwise could lead to a problem.

Comment on lines +271 to +272
Err(e) if e.source.kind() == NotFound => {
let (path, metadata) = self.generate_initial_config(s)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the deprecation warning belongs here

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.

Implement repo ownership checks In-repo configs are a potential security risk

3 participants