Patchwork [3,of,7,RFC,v2] censor: add common censorship validation routine which consults config

mail settings
Date Sept. 15, 2014, 12:01 p.m.
Message ID <>
Download mbox | patch
Permalink /patch/5820/
State Accepted
Headers show

Comments - Sept. 15, 2014, 12:01 p.m.
# HG changeset patch
# User Mike Edgar <>
# Date 1410380674 14400
#      Wed Sep 10 16:24:34 2014 -0400
# Node ID 0f5665410a9871b7303435ea3f76874a4b852e65
# Parent  79d3c249a0761c95e3cf885159d4828d73bb4074
censor: add common censorship validation routine which consults config

Some commands, upon encountering censored file contents, will want to proceed
despite the integrity violation. For example, `hg verify` should not report an
error if it expects certain file contents to be missing.

The question of whether a file revision is expected to be censored is one of
policy, and may vary by system, user and repository. The censor module will
be responsible for implementing various built-in policies, selected using the
config option "censor.allow". This change includes two choices for
censor.allow: "all" and "hgcensored".

"all" does no verification: all censored data is allowed.

"hgcensored" verifies censored file revisions against a tracked .hgcensored
file in the repository root. Censored file data should be replaced by a
pointer to a changeset in which the .hgcensored file contains the censored
file and node.

A future "signed" policy could extend "hgcensored" by requiring that the
pointed-to changeset be signed by trusted GPG certificates.


diff -r 79d3c249a076 -r 0f5665410a98 mercurial/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/	Wed Sep 10 16:24:34 2014 -0400
@@ -0,0 +1,29 @@ 
+# - support functions for retroactively censoring file revision data
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+from node import bin, hex
+import filelog
+def allowed(repo, f, node):
+    """Return whether the given file may be censored at the given revision."""
+    mode = repo.ui.config("censor", "allow", "hgcensor")
+    if mode == "all":
+        return True
+    elif mode == "hgcensor":
+        flog = repo.file(f)
+        frev = flog.rev(node)
+        meta = filelog.parsemeta(flog.censormeta(frev))[0]
+        commit = bin(meta["censored"])
+        repo.ui.note("%s claims to be censored by commit %s\n"
+                     % (f, hex(commit)))
+        if commit not in repo:
+            return False
+        censored = repo[commit].filectx('.hgcensored').data()
+        # TODO: Verify a common ancestor exists between the censored revision
+        # and the given commit which altered .hgcensored
+        expected = '%s %s' % (, hex(flog.node(frev)))
+        return expected in censored
+    else:
+        return False