-
I want to share the output of (I intend to reference this page when someone needs help but can't share their log output without redacting it). |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 2 replies
-
Add the following $ jj log -T 'separate(" ", format_short_change_id(change_id), format_short_commit_id(commit_id), description.substr(0, 10), bookmarks, tags)'
@ lnsmzzwo 82654649
│ × ymytqtlu 534d9899 wip: fetch
├─╯
○ vltpmqlm f15c46e6 my-feature*
◆ kwxqrpuv cc485aba Merged PR main
│ × nkqxupun 24ecb6eb Add anothe
│ ○ ktwkzstl 0990b2bf Add someth
├─╯ This will output just the first 10 characters of descriptions, plus bookmarks and tags. If that is sensitive information, you can omit them or redact them further, but it might be harder to figure out which revision is which: $ jj log -T 'separate(" ", format_short_change_id(change_id), format_short_commit_id(commit_id), description.substr(0, 3))' |
Beta Was this translation helpful? Give feedback.
-
I worked on this for #6492 and some patches I can't submit a PR for, so I'll share them here: diff --git a/cli/src/template_builder.rs b/cli/src/template_builder.rs
index 71d0563616..5d7d04f79d 100644
--- a/cli/src/template_builder.rs
+++ b/cli/src/template_builder.rs
@@ -14,6 +14,9 @@
use std::cmp::Ordering;
use std::collections::HashMap;
+use std::hash::DefaultHasher;
+use std::hash::Hash;
+use std::hash::Hasher;
use std::io;
use std::iter;
@@ -1634,6 +1637,18 @@
Ok(L::Property::wrap_template(template))
},
);
+ map.insert("hash",
+ |language, diagnostics, build_ctx, function| {
+ let [content_node] = function.expect_exact_arguments()?;
+ let content = expect_plain_text_expression(language, diagnostics, build_ctx, content_node)?;
+ let result = content.map(|c| {
+ let mut hasher = DefaultHasher::new();
+ c.hash(&mut hasher);
+ let id = format!("{:x}", hasher.finish());
+ id
+ });
+ Ok(result.into_dyn_wrapped())
+ });
map.insert("label", |language, diagnostics, build_ctx, function| {
let [label_node, content_node] = function.expect_exact_arguments()?;
let label_property = diff --git a/cli/src/commands/evolog.rs b/cli/src/commands/evolog.rs
index e6957627c1..24cbdb5c3c 100644
--- a/cli/src/commands/evolog.rs
+++ b/cli/src/commands/evolog.rs
@@ -88,6 +88,9 @@
patch: bool,
#[command(flatten)]
diff_format: DiffFormatArgs,
+ /// Anonymize evolog by redacting information like committer email, commit description and branch and tag names.
+ #[arg(long)]
+ anonymize: bool
}
#[instrument(skip_all)]
@@ -111,9 +114,10 @@
let node_template: TemplateRenderer<Option<Commit>>;
{
let language = workspace_command.commit_template_language();
- let template_string = match &args.template {
- Some(value) => value.to_string(),
- None => workspace_command.settings().get_string("templates.log")?,
+ let template_string = match (&args.template, &args.anonymize) {
+ (Some(value), _) => value.to_owned(), // TODO: Consider printing an error message if user uses `--anonymize` and a custom template.
+ (None, false) => workspace_command.settings().get_string("templates.log")?,
+ (None, true) => workspace_command.settings().get_string("template-aliases.builtin_log_redacted")?
};
template = workspace_command
.parse_template(ui, &language, &template_string)?
diff --git a/cli/src/commands/log.rs b/cli/src/commands/log.rs
index ccf4a195ca..bb27016896 100644
--- a/cli/src/commands/log.rs
+++ b/cli/src/commands/log.rs
@@ -116,6 +116,9 @@
patch: bool,
#[command(flatten)]
diff_format: DiffFormatArgs,
+ /// Anonymize log by redacting information like committer email, commit descriptions and branch and tag names.
+ #[arg(long)]
+ anonymize: bool
}
#[instrument(skip_all)]
@@ -165,9 +168,10 @@
let node_template: TemplateRenderer<Option<Commit>>;
{
let language = workspace_command.commit_template_language();
- let template_string = match &args.template {
- Some(value) => value.to_string(),
- None => settings.get_string("templates.log")?,
+ let template_string = match (&args.template, &args.anonymize) {
+ (Some(value), _) => value.to_string(), // TODO: Consider printing an error message if user uses `--anonymize` and a custom template
+ (None, false) => settings.get_string("templates.log")?,
+ (None, true) => settings.get_string("template-aliases.builtin_log_redacted")?
};
template = workspace_command
.parse_template(ui, &language, &template_string)?
diff --git a/cli/src/commands/operation/log.rs b/cli/src/commands/operation/log.rs
index 9b50d9df7c..ba72dc9b84 100644
--- a/cli/src/commands/operation/log.rs
+++ b/cli/src/commands/operation/log.rs
@@ -84,6 +84,9 @@
patch: bool,
#[command(flatten)]
diff_format: DiffFormatArgs,
+ /// Anonymize op log by redacting the username
+ #[arg(long)]
+ anonymize: bool
}
pub fn cmd_op_log(
@@ -127,9 +130,10 @@
Some(current_op.id()),
workspace_env.operation_template_extensions(),
);
- let text = match &args.template {
- Some(value) => value.to_owned(),
- None => settings.get_string("templates.op_log")?,
+ let text = match (&args.template, &args.anonymize) {
+ (Some(value), _) => value.to_owned(), // TODO: Consider printing an error message if user uses `--anonymize` and a custom template.
+ (None, false) => settings.get_string("templates.op_log")?,
+ (None, true) => settings.get_string("template-aliases.builtin_op_log_redacted")?
};
template = workspace_env
.parse_template(ui, &language, &text)?
diff --git a/cli/src/config/templates.toml b/cli/src/config/templates.toml
index 079cd2221f..36416cacb5 100644
--- a/cli/src/config/templates.toml
+++ b/cli/src/config/templates.toml
@@ -168,6 +168,21 @@
)
'''
+builtin_log_redacted = '''
+if(root,
+ format_root_commit(self),
+ label(if(current_working_copy, "working_copy"),
+ concat(
+ format_short_commit_header_redacted(self) ++ "\n",
+ separate(" ",
+ if(empty, label("empty", "(empty)")),
+ label("description", "(redacted)"),
+ ) ++ "\n",
+ ),
+ )
+)
+'''
+
builtin_log_compact_full_description = '''
if(root,
format_root_commit(self),
@@ -215,6 +230,7 @@
)
)
'''
+
builtin_op_log_comfortable = 'builtin_op_log_compact ++ "\n"'
builtin_op_log_oneline = '''
label(if(current_operation, "current_operation"),
@@ -225,6 +241,15 @@
)
)
'''
+builtin_op_log_redacted = '''
+label(if(current_operation, "current_operation"),
+ coalesce(
+ if(snapshot, format_operation_redacted(self)),
+ if(root, format_root_operation(self)),
+ format_operation(self),
+ )
+)
+'''
default_commit_description = '""'
description_placeholder = 'label("description placeholder", "(no description set)")'
@@ -315,6 +340,13 @@
if(op.tags(), op.tags() ++ "\n"),
)
'''
+'format_operation_redacted(op)' = '''
+concat(
+ separate(" ", format_short_operation_id(op.id()), label("user", "<REDACTED>"), format_time_range(op.time())), "\n",
+ op.description().first_line(), "\n",
+ if(op.tags(), op.tags() ++ "\n"),
+)
+'''
'format_snapshot_operation(op)' = 'format_operation(op)'
'format_root_operation(root)' = 'separate(" ", root.id().short(), label("root", "root()")) ++ "\n"'
@@ -358,6 +390,22 @@
)
'''
+'format_short_commit_header_redacted(commit)' = '''
+separate(" ",
+ format_short_change_id_with_hidden_and_divergent_info(commit),
+ label("author", "<REDACTED>"),
+ format_timestamp(commit_timestamp(commit)),
+ commit.bookmarks().map(|bookmark| concat("branch-", truncate_end(5, hash(bookmark.name())))),
+ commit.tags().map(|tag| concat("tag-", truncate_end(5, hash(tag.name())))),
+ commit.working_copies(),
+ if(commit.git_head(), label("git_head", "git_head()")),
+ format_short_commit_id(commit.commit_id()),
+ if(commit.conflict(), label("conflict", "conflict")),
+ if(config("ui.show-cryptographic-signatures").as_boolean(),
+ format_short_cryptographic_signature(commit.signature())),
+)
+''' # TODO: Possibly add some kind of repo-unique salt to the hash methods, if it makes users feel more secure (right now, `main` will always be `branch-c8c7a` for every repo)
+
'format_detailed_cryptographic_signature(signature)' = '''
if(signature,
separate(" ",
diff --git a/cli/src/template_builder.rs b/cli/src/template_builder.rs
index 5d7d04f79d..b3bc3d918e 100644
--- a/cli/src/template_builder.rs
+++ b/cli/src/template_builder.rs
@@ -1640,7 +1640,7 @@
map.insert("hash",
|language, diagnostics, build_ctx, function| {
let [content_node] = function.expect_exact_arguments()?;
- let content = expect_plain_text_expression(language, diagnostics, build_ctx, content_node)?;
+ let content = expect_stringify_expression(language, diagnostics, build_ctx, content_node)?;
let result = content.map(|c| {
let mut hasher = DefaultHasher::new();
c.hash(&mut hasher);
diff --git a/cli/tests/[email protected] b/cli/tests/[email protected]
index cc4cbc24f7..bd00edfa28 100644
--- a/cli/tests/[email protected]
+++ b/cli/tests/[email protected]
@@ -941,6 +941,7 @@
* `--context <CONTEXT>` — Number of lines of context to show
* `--ignore-all-space` — Ignore whitespace when comparing lines
* `--ignore-space-change` — Ignore changes in amount of whitespace when comparing lines
+* `--anonymize` — Anonymize evolog by redacting information like committer email, commit description and branch and tag names
@@ -1568,6 +1569,7 @@
* `--context <CONTEXT>` — Number of lines of context to show
* `--ignore-all-space` — Ignore whitespace when comparing lines
* `--ignore-space-change` — Ignore changes in amount of whitespace when comparing lines
+* `--anonymize` — Anonymize log by redacting information like committer email, commit descriptions and branch and tag names
@@ -1819,6 +1821,7 @@
* `--context <CONTEXT>` — Number of lines of context to show
* `--ignore-all-space` — Ignore whitespace when comparing lines
* `--ignore-space-change` — Ignore changes in amount of whitespace when comparing lines
+* `--anonymize` — Anonymize op log by redacting the username
diff --git a/cli/tests/test_completion.rs b/cli/tests/test_completion.rs
index e1e4c20706..8415eaae74 100644
--- a/cli/tests/test_completion.rs
+++ b/cli/tests/test_completion.rs
@@ -1073,11 +1073,13 @@
builtin_log_node
builtin_log_node_ascii
builtin_log_oneline
+ builtin_log_redacted
builtin_op_log_comfortable
builtin_op_log_compact
builtin_op_log_node
builtin_op_log_node_ascii
builtin_op_log_oneline
+ builtin_op_log_redacted
commit_summary_separator
default_commit_description
description_placeholder
diff --git a/cli/tests/test_evolog_command.rs b/cli/tests/test_evolog_command.rs
index 1baf89cc46..a46e3abeaa 100644
--- a/cli/tests/test_evolog_command.rs
+++ b/cli/tests/test_evolog_command.rs
@@ -481,11 +481,13 @@
- builtin_log_node
- builtin_log_node_ascii
- builtin_log_oneline
+ - builtin_log_redacted
- builtin_op_log_comfortable
- builtin_op_log_compact
- builtin_op_log_node
- builtin_op_log_node_ascii
- builtin_op_log_oneline
+ - builtin_op_log_redacted
- commit_summary_separator
- default_commit_description
- description_placeholder
diff --git a/cli/tests/test_log_command.rs b/cli/tests/test_log_command.rs
index 17dedb50b7..f5dbf76249 100644
--- a/cli/tests/test_log_command.rs
+++ b/cli/tests/test_log_command.rs
@@ -55,11 +55,13 @@
- builtin_log_node
- builtin_log_node_ascii
- builtin_log_oneline
+ - builtin_log_redacted
- builtin_op_log_comfortable
- builtin_op_log_compact
- builtin_op_log_node
- builtin_op_log_node_ascii
- builtin_op_log_oneline
+ - builtin_op_log_redacted
- commit_summary_separator
- default_commit_description
- description_placeholder
diff --git a/cli/tests/test_operations.rs b/cli/tests/test_operations.rs
index 2acc4747c1..0606b47794 100644
--- a/cli/tests/test_operations.rs
+++ b/cli/tests/test_operations.rs
@@ -200,11 +200,13 @@
- builtin_log_node
- builtin_log_node_ascii
- builtin_log_oneline
+ - builtin_log_redacted
- builtin_op_log_comfortable
- builtin_op_log_compact
- builtin_op_log_node
- builtin_op_log_node_ascii
- builtin_op_log_oneline
+ - builtin_op_log_redacted
- commit_summary_separator
- default_commit_description
- description_placeholder
diff --git a/cli/tests/test_show_command.rs b/cli/tests/test_show_command.rs
index 6f8cc01d01..dcab955296 100644
--- a/cli/tests/test_show_command.rs
+++ b/cli/tests/test_show_command.rs
@@ -316,11 +316,13 @@
- builtin_log_node
- builtin_log_node_ascii
- builtin_log_oneline
+ - builtin_log_redacted
- builtin_op_log_comfortable
- builtin_op_log_compact
- builtin_op_log_node
- builtin_op_log_node_ascii
- builtin_op_log_oneline
+ - builtin_op_log_redacted
- commit_summary_separator
- default_commit_description
- description_placeholder
diff --git a/cli/tests/test_templater.rs b/cli/tests/test_templater.rs
index 6cf9bf4e4e..a827d94b88 100644
--- a/cli/tests/test_templater.rs
+++ b/cli/tests/test_templater.rs
@@ -146,7 +146,7 @@
| ^-----^
|
= Keyword `builtin` doesn't exist
- Hint: Did you mean `builtin_config_list`, `builtin_config_list_detailed`, `builtin_draft_commit_description`, `builtin_log_comfortable`, `builtin_log_compact`, `builtin_log_compact_full_description`, `builtin_log_detailed`, `builtin_log_node`, `builtin_log_node_ascii`, `builtin_log_oneline`, `builtin_op_log_comfortable`, `builtin_op_log_compact`, `builtin_op_log_node`, `builtin_op_log_node_ascii`, `builtin_op_log_oneline`?
+ Hint: Did you mean `builtin_config_list`, `builtin_config_list_detailed`, `builtin_draft_commit_description`, `builtin_log_comfortable`, `builtin_log_compact`, `builtin_log_compact_full_description`, `builtin_log_detailed`, `builtin_log_node`, `builtin_log_node_ascii`, `builtin_log_oneline`, `builtin_log_redacted`, `builtin_op_log_comfortable`, `builtin_op_log_compact`, `builtin_op_log_node`, `builtin_op_log_node_ascii`, `builtin_op_log_oneline`, `builtin_op_log_redacted`?
[EOF]
[exit status: 1]
");
diff --git a/docs/templates.md b/docs/templates.md
index 928393d371..6b4aaa88cb 100644
--- a/docs/templates.md
+++ b/docs/templates.md
@@ -91,6 +91,8 @@
* `surround(prefix: Template, suffix: Template, content: Template) -> Template`:
Surround **non-empty** content with texts such as parentheses.
* `config(name: String) -> ConfigValue`: Look up configuration value by `name`.
+* `hash(content: Template) -> Template`:
+ Hash the input and return a hexadecimal string representation of the digest.
## Types After patching, simply pass the If you find this useful, please consider submitting it as a PR for me. If you're worried about ownership issues, according to ChatGPT, I'm supposed to say something like "I hereby waive any and all copyright and related rights in this contribution, placing it into the public domain so you may freely incorporate, modify, and submit it under your own name or preferred license.". So yeah, that's it, go ahead and do it. |
Beta Was this translation helpful? Give feedback.
-
With jj 0.33.0, it will be possible to redact the sensitive data from the logs with a builtin template:
|
Beta Was this translation helpful? Give feedback.
With jj 0.33.0, it will be possible to redact the sensitive data from the logs with a builtin template:
jj log -Tbuiltin_log_redacted
jj evolog -Tbuiltin_log_redacted
jj op log -Tbuiltin_op_log_redacted