##// END OF EJS Templates
censor: make various path forms available like other Mercurial commands...
FUJIWARA Katsunori -
r25806:5e18f6e3 default
parent child Browse files
Show More
@@ -1,165 +1,170 b''
1 # Copyright (C) 2015 - Mike Edgar <adgar@google.com>
1 # Copyright (C) 2015 - Mike Edgar <adgar@google.com>
2 #
2 #
3 # This extension enables removal of file content at a given revision,
3 # This extension enables removal of file content at a given revision,
4 # rewriting the data/metadata of successive revisions to preserve revision log
4 # rewriting the data/metadata of successive revisions to preserve revision log
5 # integrity.
5 # integrity.
6
6
7 """erase file content at a given revision
7 """erase file content at a given revision
8
8
9 The censor command instructs Mercurial to erase all content of a file at a given
9 The censor command instructs Mercurial to erase all content of a file at a given
10 revision *without updating the changeset hash.* This allows existing history to
10 revision *without updating the changeset hash.* This allows existing history to
11 remain valid while preventing future clones/pulls from receiving the erased
11 remain valid while preventing future clones/pulls from receiving the erased
12 data.
12 data.
13
13
14 Typical uses for censor are due to security or legal requirements, including::
14 Typical uses for censor are due to security or legal requirements, including::
15
15
16 * Passwords, private keys, crytographic material
16 * Passwords, private keys, crytographic material
17 * Licensed data/code/libraries for which the license has expired
17 * Licensed data/code/libraries for which the license has expired
18 * Personally Identifiable Information or other private data
18 * Personally Identifiable Information or other private data
19
19
20 Censored nodes can interrupt mercurial's typical operation whenever the excised
20 Censored nodes can interrupt mercurial's typical operation whenever the excised
21 data needs to be materialized. Some commands, like ``hg cat``/``hg revert``,
21 data needs to be materialized. Some commands, like ``hg cat``/``hg revert``,
22 simply fail when asked to produce censored data. Others, like ``hg verify`` and
22 simply fail when asked to produce censored data. Others, like ``hg verify`` and
23 ``hg update``, must be capable of tolerating censored data to continue to
23 ``hg update``, must be capable of tolerating censored data to continue to
24 function in a meaningful way. Such commands only tolerate censored file
24 function in a meaningful way. Such commands only tolerate censored file
25 revisions if they are allowed by the "censor.policy=ignore" config option.
25 revisions if they are allowed by the "censor.policy=ignore" config option.
26 """
26 """
27
27
28 from mercurial.node import short
28 from mercurial.node import short
29 from mercurial import cmdutil, error, filelog, revlog, scmutil, util
29 from mercurial import cmdutil, error, filelog, revlog, scmutil, util
30 from mercurial.i18n import _
30 from mercurial.i18n import _
31
31
32 cmdtable = {}
32 cmdtable = {}
33 command = cmdutil.command(cmdtable)
33 command = cmdutil.command(cmdtable)
34 # Note for extension authors: ONLY specify testedwith = 'internal' for
34 # Note for extension authors: ONLY specify testedwith = 'internal' for
35 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
35 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
36 # be specifying the version(s) of Mercurial they are tested with, or
36 # be specifying the version(s) of Mercurial they are tested with, or
37 # leave the attribute unspecified.
37 # leave the attribute unspecified.
38 testedwith = 'internal'
38 testedwith = 'internal'
39
39
40 @command('censor',
40 @command('censor',
41 [('r', 'rev', '', _('censor file from specified revision'), _('REV')),
41 [('r', 'rev', '', _('censor file from specified revision'), _('REV')),
42 ('t', 'tombstone', '', _('replacement tombstone data'), _('TEXT'))],
42 ('t', 'tombstone', '', _('replacement tombstone data'), _('TEXT'))],
43 _('-r REV [-t TEXT] [FILE]'))
43 _('-r REV [-t TEXT] [FILE]'))
44 def censor(ui, repo, path, rev='', tombstone='', **opts):
44 def censor(ui, repo, path, rev='', tombstone='', **opts):
45 if not path:
45 if not path:
46 raise util.Abort(_('must specify file path to censor'))
46 raise util.Abort(_('must specify file path to censor'))
47 if not rev:
47 if not rev:
48 raise util.Abort(_('must specify revision to censor'))
48 raise util.Abort(_('must specify revision to censor'))
49
49
50 wctx = repo[None]
51
52 m = scmutil.match(wctx, (path,))
53 if m.anypats() or len(m.files()) != 1:
54 raise util.Abort(_('can only specify an explicit filename'))
55 path = m.files()[0]
50 flog = repo.file(path)
56 flog = repo.file(path)
51 if not len(flog):
57 if not len(flog):
52 raise util.Abort(_('cannot censor file with no history'))
58 raise util.Abort(_('cannot censor file with no history'))
53
59
54 rev = scmutil.revsingle(repo, rev, rev).rev()
60 rev = scmutil.revsingle(repo, rev, rev).rev()
55 try:
61 try:
56 ctx = repo[rev]
62 ctx = repo[rev]
57 except KeyError:
63 except KeyError:
58 raise util.Abort(_('invalid revision identifier %s') % rev)
64 raise util.Abort(_('invalid revision identifier %s') % rev)
59
65
60 try:
66 try:
61 fctx = ctx.filectx(path)
67 fctx = ctx.filectx(path)
62 except error.LookupError:
68 except error.LookupError:
63 raise util.Abort(_('file does not exist at revision %s') % rev)
69 raise util.Abort(_('file does not exist at revision %s') % rev)
64
70
65 fnode = fctx.filenode()
71 fnode = fctx.filenode()
66 headctxs = [repo[c] for c in repo.heads()]
72 headctxs = [repo[c] for c in repo.heads()]
67 heads = [c for c in headctxs if path in c and c.filenode(path) == fnode]
73 heads = [c for c in headctxs if path in c and c.filenode(path) == fnode]
68 if heads:
74 if heads:
69 headlist = ', '.join([short(c.node()) for c in heads])
75 headlist = ', '.join([short(c.node()) for c in heads])
70 raise util.Abort(_('cannot censor file in heads (%s)') % headlist,
76 raise util.Abort(_('cannot censor file in heads (%s)') % headlist,
71 hint=_('clean/delete and commit first'))
77 hint=_('clean/delete and commit first'))
72
78
73 wctx = repo[None]
74 wp = wctx.parents()
79 wp = wctx.parents()
75 if ctx.node() in [p.node() for p in wp]:
80 if ctx.node() in [p.node() for p in wp]:
76 raise util.Abort(_('cannot censor working directory'),
81 raise util.Abort(_('cannot censor working directory'),
77 hint=_('clean/delete/update first'))
82 hint=_('clean/delete/update first'))
78
83
79 flogv = flog.version & 0xFFFF
84 flogv = flog.version & 0xFFFF
80 if flogv != revlog.REVLOGNG:
85 if flogv != revlog.REVLOGNG:
81 raise util.Abort(
86 raise util.Abort(
82 _('censor does not support revlog version %d') % (flogv,))
87 _('censor does not support revlog version %d') % (flogv,))
83
88
84 tombstone = filelog.packmeta({"censored": tombstone}, "")
89 tombstone = filelog.packmeta({"censored": tombstone}, "")
85
90
86 crev = fctx.filerev()
91 crev = fctx.filerev()
87
92
88 if len(tombstone) > flog.rawsize(crev):
93 if len(tombstone) > flog.rawsize(crev):
89 raise util.Abort(_(
94 raise util.Abort(_(
90 'censor tombstone must be no longer than censored data'))
95 'censor tombstone must be no longer than censored data'))
91
96
92 # Using two files instead of one makes it easy to rewrite entry-by-entry
97 # Using two files instead of one makes it easy to rewrite entry-by-entry
93 idxread = repo.svfs(flog.indexfile, 'r')
98 idxread = repo.svfs(flog.indexfile, 'r')
94 idxwrite = repo.svfs(flog.indexfile, 'wb', atomictemp=True)
99 idxwrite = repo.svfs(flog.indexfile, 'wb', atomictemp=True)
95 if flog.version & revlog.REVLOGNGINLINEDATA:
100 if flog.version & revlog.REVLOGNGINLINEDATA:
96 dataread, datawrite = idxread, idxwrite
101 dataread, datawrite = idxread, idxwrite
97 else:
102 else:
98 dataread = repo.svfs(flog.datafile, 'r')
103 dataread = repo.svfs(flog.datafile, 'r')
99 datawrite = repo.svfs(flog.datafile, 'wb', atomictemp=True)
104 datawrite = repo.svfs(flog.datafile, 'wb', atomictemp=True)
100
105
101 # Copy all revlog data up to the entry to be censored.
106 # Copy all revlog data up to the entry to be censored.
102 rio = revlog.revlogio()
107 rio = revlog.revlogio()
103 offset = flog.start(crev)
108 offset = flog.start(crev)
104
109
105 for chunk in util.filechunkiter(idxread, limit=crev * rio.size):
110 for chunk in util.filechunkiter(idxread, limit=crev * rio.size):
106 idxwrite.write(chunk)
111 idxwrite.write(chunk)
107 for chunk in util.filechunkiter(dataread, limit=offset):
112 for chunk in util.filechunkiter(dataread, limit=offset):
108 datawrite.write(chunk)
113 datawrite.write(chunk)
109
114
110 def rewriteindex(r, newoffs, newdata=None):
115 def rewriteindex(r, newoffs, newdata=None):
111 """Rewrite the index entry with a new data offset and optional new data.
116 """Rewrite the index entry with a new data offset and optional new data.
112
117
113 The newdata argument, if given, is a tuple of three positive integers:
118 The newdata argument, if given, is a tuple of three positive integers:
114 (new compressed, new uncompressed, added flag bits).
119 (new compressed, new uncompressed, added flag bits).
115 """
120 """
116 offlags, comp, uncomp, base, link, p1, p2, nodeid = flog.index[r]
121 offlags, comp, uncomp, base, link, p1, p2, nodeid = flog.index[r]
117 flags = revlog.gettype(offlags)
122 flags = revlog.gettype(offlags)
118 if newdata:
123 if newdata:
119 comp, uncomp, nflags = newdata
124 comp, uncomp, nflags = newdata
120 flags |= nflags
125 flags |= nflags
121 offlags = revlog.offset_type(newoffs, flags)
126 offlags = revlog.offset_type(newoffs, flags)
122 e = (offlags, comp, uncomp, r, link, p1, p2, nodeid)
127 e = (offlags, comp, uncomp, r, link, p1, p2, nodeid)
123 idxwrite.write(rio.packentry(e, None, flog.version, r))
128 idxwrite.write(rio.packentry(e, None, flog.version, r))
124 idxread.seek(rio.size, 1)
129 idxread.seek(rio.size, 1)
125
130
126 def rewrite(r, offs, data, nflags=revlog.REVIDX_DEFAULT_FLAGS):
131 def rewrite(r, offs, data, nflags=revlog.REVIDX_DEFAULT_FLAGS):
127 """Write the given full text to the filelog with the given data offset.
132 """Write the given full text to the filelog with the given data offset.
128
133
129 Returns:
134 Returns:
130 The integer number of data bytes written, for tracking data offsets.
135 The integer number of data bytes written, for tracking data offsets.
131 """
136 """
132 flag, compdata = flog.compress(data)
137 flag, compdata = flog.compress(data)
133 newcomp = len(flag) + len(compdata)
138 newcomp = len(flag) + len(compdata)
134 rewriteindex(r, offs, (newcomp, len(data), nflags))
139 rewriteindex(r, offs, (newcomp, len(data), nflags))
135 datawrite.write(flag)
140 datawrite.write(flag)
136 datawrite.write(compdata)
141 datawrite.write(compdata)
137 dataread.seek(flog.length(r), 1)
142 dataread.seek(flog.length(r), 1)
138 return newcomp
143 return newcomp
139
144
140 # Rewrite censored revlog entry with (padded) tombstone data.
145 # Rewrite censored revlog entry with (padded) tombstone data.
141 pad = ' ' * (flog.rawsize(crev) - len(tombstone))
146 pad = ' ' * (flog.rawsize(crev) - len(tombstone))
142 offset += rewrite(crev, offset, tombstone + pad, revlog.REVIDX_ISCENSORED)
147 offset += rewrite(crev, offset, tombstone + pad, revlog.REVIDX_ISCENSORED)
143
148
144 # Rewrite all following filelog revisions fixing up offsets and deltas.
149 # Rewrite all following filelog revisions fixing up offsets and deltas.
145 for srev in xrange(crev + 1, len(flog)):
150 for srev in xrange(crev + 1, len(flog)):
146 if crev in flog.parentrevs(srev):
151 if crev in flog.parentrevs(srev):
147 # Immediate children of censored node must be re-added as fulltext.
152 # Immediate children of censored node must be re-added as fulltext.
148 try:
153 try:
149 revdata = flog.revision(srev)
154 revdata = flog.revision(srev)
150 except error.CensoredNodeError as e:
155 except error.CensoredNodeError as e:
151 revdata = e.tombstone
156 revdata = e.tombstone
152 dlen = rewrite(srev, offset, revdata)
157 dlen = rewrite(srev, offset, revdata)
153 else:
158 else:
154 # Copy any other revision data verbatim after fixing up the offset.
159 # Copy any other revision data verbatim after fixing up the offset.
155 rewriteindex(srev, offset)
160 rewriteindex(srev, offset)
156 dlen = flog.length(srev)
161 dlen = flog.length(srev)
157 for chunk in util.filechunkiter(dataread, limit=dlen):
162 for chunk in util.filechunkiter(dataread, limit=dlen):
158 datawrite.write(chunk)
163 datawrite.write(chunk)
159 offset += dlen
164 offset += dlen
160
165
161 idxread.close()
166 idxread.close()
162 idxwrite.close()
167 idxwrite.close()
163 if dataread is not idxread:
168 if dataread is not idxread:
164 dataread.close()
169 dataread.close()
165 datawrite.close()
170 datawrite.close()
@@ -1,480 +1,485 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extensions]
2 > [extensions]
3 > censor=
3 > censor=
4 > EOF
4 > EOF
5 $ cp $HGRCPATH $HGRCPATH.orig
5 $ cp $HGRCPATH $HGRCPATH.orig
6
6
7 Create repo with unimpeachable content
7 Create repo with unimpeachable content
8
8
9 $ hg init r
9 $ hg init r
10 $ cd r
10 $ cd r
11 $ echo 'Initially untainted file' > target
11 $ echo 'Initially untainted file' > target
12 $ echo 'Normal file here' > bystander
12 $ echo 'Normal file here' > bystander
13 $ hg add target bystander
13 $ hg add target bystander
14 $ hg ci -m init
14 $ hg ci -m init
15
15
16 Clone repo so we can test pull later
16 Clone repo so we can test pull later
17
17
18 $ cd ..
18 $ cd ..
19 $ hg clone r rpull
19 $ hg clone r rpull
20 updating to branch default
20 updating to branch default
21 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
22 $ cd r
22 $ cd r
23
23
24 Introduce content which will ultimately require censorship. Name the first
24 Introduce content which will ultimately require censorship. Name the first
25 censored node C1, second C2, and so on
25 censored node C1, second C2, and so on
26
26
27 $ echo 'Tainted file' > target
27 $ echo 'Tainted file' > target
28 $ echo 'Passwords: hunter2' >> target
28 $ echo 'Passwords: hunter2' >> target
29 $ hg ci -m taint target
29 $ hg ci -m taint target
30 $ C1=`hg id --debug -i`
30 $ C1=`hg id --debug -i`
31
31
32 $ echo 'hunter3' >> target
32 $ echo 'hunter3' >> target
33 $ echo 'Normal file v2' > bystander
33 $ echo 'Normal file v2' > bystander
34 $ hg ci -m moretaint target bystander
34 $ hg ci -m moretaint target bystander
35 $ C2=`hg id --debug -i`
35 $ C2=`hg id --debug -i`
36
36
37 Add a new sanitized versions to correct our mistake. Name the first head H1,
37 Add a new sanitized versions to correct our mistake. Name the first head H1,
38 the second head H2, and so on
38 the second head H2, and so on
39
39
40 $ echo 'Tainted file is now sanitized' > target
40 $ echo 'Tainted file is now sanitized' > target
41 $ hg ci -m sanitized target
41 $ hg ci -m sanitized target
42 $ H1=`hg id --debug -i`
42 $ H1=`hg id --debug -i`
43
43
44 $ hg update -r $C2
44 $ hg update -r $C2
45 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
45 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
46 $ echo 'Tainted file now super sanitized' > target
46 $ echo 'Tainted file now super sanitized' > target
47 $ hg ci -m 'super sanitized' target
47 $ hg ci -m 'super sanitized' target
48 created new head
48 created new head
49 $ H2=`hg id --debug -i`
49 $ H2=`hg id --debug -i`
50
50
51 Verify target contents before censorship at each revision
51 Verify target contents before censorship at each revision
52
52
53 $ hg cat -r $H1 target
53 $ hg cat -r $H1 target
54 Tainted file is now sanitized
54 Tainted file is now sanitized
55 $ hg cat -r $H2 target
55 $ hg cat -r $H2 target
56 Tainted file now super sanitized
56 Tainted file now super sanitized
57 $ hg cat -r $C2 target
57 $ hg cat -r $C2 target
58 Tainted file
58 Tainted file
59 Passwords: hunter2
59 Passwords: hunter2
60 hunter3
60 hunter3
61 $ hg cat -r $C1 target
61 $ hg cat -r $C1 target
62 Tainted file
62 Tainted file
63 Passwords: hunter2
63 Passwords: hunter2
64 $ hg cat -r 0 target
64 $ hg cat -r 0 target
65 Initially untainted file
65 Initially untainted file
66
66
67 Try to censor revision with too large of a tombstone message
67 Try to censor revision with too large of a tombstone message
68
68
69 $ hg censor -r $C1 -t 'blah blah blah blah blah blah blah blah bla' target
69 $ hg censor -r $C1 -t 'blah blah blah blah blah blah blah blah bla' target
70 abort: censor tombstone must be no longer than censored data
70 abort: censor tombstone must be no longer than censored data
71 [255]
71 [255]
72
72
73 Censor revision with 2 offenses
73 Censor revision with 2 offenses
74
74
75 $ hg censor -r $C2 -t "remove password" target
75 (this also tests file pattern matching: path relative to cwd case)
76
77 $ mkdir -p foo/bar/baz
78 $ hg --cwd foo/bar/baz censor -r $C2 -t "remove password" ../../../target
76 $ hg cat -r $H1 target
79 $ hg cat -r $H1 target
77 Tainted file is now sanitized
80 Tainted file is now sanitized
78 $ hg cat -r $H2 target
81 $ hg cat -r $H2 target
79 Tainted file now super sanitized
82 Tainted file now super sanitized
80 $ hg cat -r $C2 target
83 $ hg cat -r $C2 target
81 abort: censored node: 1e0247a9a4b7
84 abort: censored node: 1e0247a9a4b7
82 (set censor.policy to ignore errors)
85 (set censor.policy to ignore errors)
83 [255]
86 [255]
84 $ hg cat -r $C1 target
87 $ hg cat -r $C1 target
85 Tainted file
88 Tainted file
86 Passwords: hunter2
89 Passwords: hunter2
87 $ hg cat -r 0 target
90 $ hg cat -r 0 target
88 Initially untainted file
91 Initially untainted file
89
92
90 Censor revision with 1 offense
93 Censor revision with 1 offense
91
94
92 $ hg censor -r $C1 target
95 (this also tests file pattern matching: with 'path:' scheme)
96
97 $ hg --cwd foo/bar/baz censor -r $C1 path:target
93 $ hg cat -r $H1 target
98 $ hg cat -r $H1 target
94 Tainted file is now sanitized
99 Tainted file is now sanitized
95 $ hg cat -r $H2 target
100 $ hg cat -r $H2 target
96 Tainted file now super sanitized
101 Tainted file now super sanitized
97 $ hg cat -r $C2 target
102 $ hg cat -r $C2 target
98 abort: censored node: 1e0247a9a4b7
103 abort: censored node: 1e0247a9a4b7
99 (set censor.policy to ignore errors)
104 (set censor.policy to ignore errors)
100 [255]
105 [255]
101 $ hg cat -r $C1 target
106 $ hg cat -r $C1 target
102 abort: censored node: 613bc869fceb
107 abort: censored node: 613bc869fceb
103 (set censor.policy to ignore errors)
108 (set censor.policy to ignore errors)
104 [255]
109 [255]
105 $ hg cat -r 0 target
110 $ hg cat -r 0 target
106 Initially untainted file
111 Initially untainted file
107
112
108 Can only checkout target at uncensored revisions, -X is workaround for --all
113 Can only checkout target at uncensored revisions, -X is workaround for --all
109
114
110 $ hg revert -r $C2 target
115 $ hg revert -r $C2 target
111 abort: censored node: 1e0247a9a4b7
116 abort: censored node: 1e0247a9a4b7
112 (set censor.policy to ignore errors)
117 (set censor.policy to ignore errors)
113 [255]
118 [255]
114 $ hg revert -r $C1 target
119 $ hg revert -r $C1 target
115 abort: censored node: 613bc869fceb
120 abort: censored node: 613bc869fceb
116 (set censor.policy to ignore errors)
121 (set censor.policy to ignore errors)
117 [255]
122 [255]
118 $ hg revert -r $C1 --all
123 $ hg revert -r $C1 --all
119 reverting bystander
124 reverting bystander
120 reverting target
125 reverting target
121 abort: censored node: 613bc869fceb
126 abort: censored node: 613bc869fceb
122 (set censor.policy to ignore errors)
127 (set censor.policy to ignore errors)
123 [255]
128 [255]
124 $ hg revert -r $C1 --all -X target
129 $ hg revert -r $C1 --all -X target
125 $ cat target
130 $ cat target
126 Tainted file now super sanitized
131 Tainted file now super sanitized
127 $ hg revert -r 0 --all
132 $ hg revert -r 0 --all
128 reverting target
133 reverting target
129 $ cat target
134 $ cat target
130 Initially untainted file
135 Initially untainted file
131 $ hg revert -r $H2 --all
136 $ hg revert -r $H2 --all
132 reverting bystander
137 reverting bystander
133 reverting target
138 reverting target
134 $ cat target
139 $ cat target
135 Tainted file now super sanitized
140 Tainted file now super sanitized
136
141
137 Uncensored file can be viewed at any revision
142 Uncensored file can be viewed at any revision
138
143
139 $ hg cat -r $H1 bystander
144 $ hg cat -r $H1 bystander
140 Normal file v2
145 Normal file v2
141 $ hg cat -r $C2 bystander
146 $ hg cat -r $C2 bystander
142 Normal file v2
147 Normal file v2
143 $ hg cat -r $C1 bystander
148 $ hg cat -r $C1 bystander
144 Normal file here
149 Normal file here
145 $ hg cat -r 0 bystander
150 $ hg cat -r 0 bystander
146 Normal file here
151 Normal file here
147
152
148 Can update to children of censored revision
153 Can update to children of censored revision
149
154
150 $ hg update -r $H1
155 $ hg update -r $H1
151 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
156 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
152 $ cat target
157 $ cat target
153 Tainted file is now sanitized
158 Tainted file is now sanitized
154 $ hg update -r $H2
159 $ hg update -r $H2
155 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
160 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
156 $ cat target
161 $ cat target
157 Tainted file now super sanitized
162 Tainted file now super sanitized
158
163
159 Set censor policy to abort in trusted $HGRC so hg verify fails
164 Set censor policy to abort in trusted $HGRC so hg verify fails
160
165
161 $ cp $HGRCPATH.orig $HGRCPATH
166 $ cp $HGRCPATH.orig $HGRCPATH
162 $ cat >> $HGRCPATH <<EOF
167 $ cat >> $HGRCPATH <<EOF
163 > [censor]
168 > [censor]
164 > policy = abort
169 > policy = abort
165 > EOF
170 > EOF
166
171
167 Repo fails verification due to censorship
172 Repo fails verification due to censorship
168
173
169 $ hg verify
174 $ hg verify
170 checking changesets
175 checking changesets
171 checking manifests
176 checking manifests
172 crosschecking files in changesets and manifests
177 crosschecking files in changesets and manifests
173 checking files
178 checking files
174 target@1: censored file data
179 target@1: censored file data
175 target@2: censored file data
180 target@2: censored file data
176 2 files, 5 changesets, 7 total revisions
181 2 files, 5 changesets, 7 total revisions
177 2 integrity errors encountered!
182 2 integrity errors encountered!
178 (first damaged changeset appears to be 1)
183 (first damaged changeset appears to be 1)
179 [1]
184 [1]
180
185
181 Cannot update to revision with censored data
186 Cannot update to revision with censored data
182
187
183 $ hg update -r $C2
188 $ hg update -r $C2
184 abort: censored node: 1e0247a9a4b7
189 abort: censored node: 1e0247a9a4b7
185 (set censor.policy to ignore errors)
190 (set censor.policy to ignore errors)
186 [255]
191 [255]
187 $ hg update -r $C1
192 $ hg update -r $C1
188 abort: censored node: 613bc869fceb
193 abort: censored node: 613bc869fceb
189 (set censor.policy to ignore errors)
194 (set censor.policy to ignore errors)
190 [255]
195 [255]
191 $ hg update -r 0
196 $ hg update -r 0
192 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
197 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
193 $ hg update -r $H2
198 $ hg update -r $H2
194 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
199 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
195
200
196 Set censor policy to ignore in trusted $HGRC so hg verify passes
201 Set censor policy to ignore in trusted $HGRC so hg verify passes
197
202
198 $ cp $HGRCPATH.orig $HGRCPATH
203 $ cp $HGRCPATH.orig $HGRCPATH
199 $ cat >> $HGRCPATH <<EOF
204 $ cat >> $HGRCPATH <<EOF
200 > [censor]
205 > [censor]
201 > policy = ignore
206 > policy = ignore
202 > EOF
207 > EOF
203
208
204 Repo passes verification with warnings with explicit config
209 Repo passes verification with warnings with explicit config
205
210
206 $ hg verify
211 $ hg verify
207 checking changesets
212 checking changesets
208 checking manifests
213 checking manifests
209 crosschecking files in changesets and manifests
214 crosschecking files in changesets and manifests
210 checking files
215 checking files
211 2 files, 5 changesets, 7 total revisions
216 2 files, 5 changesets, 7 total revisions
212
217
213 May update to revision with censored data with explicit config
218 May update to revision with censored data with explicit config
214
219
215 $ hg update -r $C2
220 $ hg update -r $C2
216 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
221 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
217 $ cat target
222 $ cat target
218 $ hg update -r $C1
223 $ hg update -r $C1
219 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
224 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
220 $ cat target
225 $ cat target
221 $ hg update -r 0
226 $ hg update -r 0
222 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
227 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
223 $ cat target
228 $ cat target
224 Initially untainted file
229 Initially untainted file
225 $ hg update -r $H2
230 $ hg update -r $H2
226 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
231 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
227 $ cat target
232 $ cat target
228 Tainted file now super sanitized
233 Tainted file now super sanitized
229
234
230 Can merge in revision with censored data. Test requires one branch of history
235 Can merge in revision with censored data. Test requires one branch of history
231 with the file censored, but we can't censor at a head, so advance H1.
236 with the file censored, but we can't censor at a head, so advance H1.
232
237
233 $ hg update -r $H1
238 $ hg update -r $H1
234 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
239 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
235 $ C3=$H1
240 $ C3=$H1
236 $ echo 'advanced head H1' > target
241 $ echo 'advanced head H1' > target
237 $ hg ci -m 'advance head H1' target
242 $ hg ci -m 'advance head H1' target
238 $ H1=`hg id --debug -i`
243 $ H1=`hg id --debug -i`
239 $ hg censor -r $C3 target
244 $ hg censor -r $C3 target
240 $ hg update -r $H2
245 $ hg update -r $H2
241 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
246 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
242 $ hg merge -r $C3
247 $ hg merge -r $C3
243 merging target
248 merging target
244 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
249 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
245 (branch merge, don't forget to commit)
250 (branch merge, don't forget to commit)
246
251
247 Revisions present in repository heads may not be censored
252 Revisions present in repository heads may not be censored
248
253
249 $ hg update -C -r $H2
254 $ hg update -C -r $H2
250 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
255 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
251 $ hg censor -r $H2 target
256 $ hg censor -r $H2 target
252 abort: cannot censor file in heads (78a8fc215e79)
257 abort: cannot censor file in heads (78a8fc215e79)
253 (clean/delete and commit first)
258 (clean/delete and commit first)
254 [255]
259 [255]
255 $ echo 'twiddling thumbs' > bystander
260 $ echo 'twiddling thumbs' > bystander
256 $ hg ci -m 'bystander commit'
261 $ hg ci -m 'bystander commit'
257 $ H2=`hg id --debug -i`
262 $ H2=`hg id --debug -i`
258 $ hg censor -r "$H2^" target
263 $ hg censor -r "$H2^" target
259 abort: cannot censor file in heads (efbe78065929)
264 abort: cannot censor file in heads (efbe78065929)
260 (clean/delete and commit first)
265 (clean/delete and commit first)
261 [255]
266 [255]
262
267
263 Cannot censor working directory
268 Cannot censor working directory
264
269
265 $ echo 'seriously no passwords' > target
270 $ echo 'seriously no passwords' > target
266 $ hg ci -m 'extend second head arbitrarily' target
271 $ hg ci -m 'extend second head arbitrarily' target
267 $ H2=`hg id --debug -i`
272 $ H2=`hg id --debug -i`
268 $ hg update -r "$H2^"
273 $ hg update -r "$H2^"
269 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
274 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
270 $ hg censor -r . target
275 $ hg censor -r . target
271 abort: cannot censor working directory
276 abort: cannot censor working directory
272 (clean/delete/update first)
277 (clean/delete/update first)
273 [255]
278 [255]
274 $ hg update -r $H2
279 $ hg update -r $H2
275 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
280 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
276
281
277 Can re-add file after being deleted + censored
282 Can re-add file after being deleted + censored
278
283
279 $ C4=$H2
284 $ C4=$H2
280 $ hg rm target
285 $ hg rm target
281 $ hg ci -m 'delete target so it may be censored'
286 $ hg ci -m 'delete target so it may be censored'
282 $ H2=`hg id --debug -i`
287 $ H2=`hg id --debug -i`
283 $ hg censor -r $C4 target
288 $ hg censor -r $C4 target
284 $ hg cat -r $C4 target
289 $ hg cat -r $C4 target
285 $ hg cat -r "$H2^^" target
290 $ hg cat -r "$H2^^" target
286 Tainted file now super sanitized
291 Tainted file now super sanitized
287 $ echo 'fresh start' > target
292 $ echo 'fresh start' > target
288 $ hg add target
293 $ hg add target
289 $ hg ci -m reincarnated target
294 $ hg ci -m reincarnated target
290 $ H2=`hg id --debug -i`
295 $ H2=`hg id --debug -i`
291 $ hg cat -r $H2 target
296 $ hg cat -r $H2 target
292 fresh start
297 fresh start
293 $ hg cat -r "$H2^" target
298 $ hg cat -r "$H2^" target
294 target: no such file in rev 452ec1762369
299 target: no such file in rev 452ec1762369
295 [1]
300 [1]
296 $ hg cat -r $C4 target
301 $ hg cat -r $C4 target
297 $ hg cat -r "$H2^^^" target
302 $ hg cat -r "$H2^^^" target
298 Tainted file now super sanitized
303 Tainted file now super sanitized
299
304
300 Can censor after revlog has expanded to no longer permit inline storage
305 Can censor after revlog has expanded to no longer permit inline storage
301
306
302 $ for x in `python $TESTDIR/seq.py 0 50000`
307 $ for x in `python $TESTDIR/seq.py 0 50000`
303 > do
308 > do
304 > echo "Password: hunter$x" >> target
309 > echo "Password: hunter$x" >> target
305 > done
310 > done
306 $ hg ci -m 'add 100k passwords'
311 $ hg ci -m 'add 100k passwords'
307 $ H2=`hg id --debug -i`
312 $ H2=`hg id --debug -i`
308 $ C5=$H2
313 $ C5=$H2
309 $ hg revert -r "$H2^" target
314 $ hg revert -r "$H2^" target
310 $ hg ci -m 'cleaned 100k passwords'
315 $ hg ci -m 'cleaned 100k passwords'
311 $ H2=`hg id --debug -i`
316 $ H2=`hg id --debug -i`
312 $ hg censor -r $C5 target
317 $ hg censor -r $C5 target
313 $ hg cat -r $C5 target
318 $ hg cat -r $C5 target
314 $ hg cat -r $H2 target
319 $ hg cat -r $H2 target
315 fresh start
320 fresh start
316
321
317 Repo with censored nodes can be cloned and cloned nodes are censored
322 Repo with censored nodes can be cloned and cloned nodes are censored
318
323
319 $ cd ..
324 $ cd ..
320 $ hg clone r rclone
325 $ hg clone r rclone
321 updating to branch default
326 updating to branch default
322 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
327 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
323 $ cd rclone
328 $ cd rclone
324 $ hg cat -r $H1 target
329 $ hg cat -r $H1 target
325 advanced head H1
330 advanced head H1
326 $ hg cat -r $H2~5 target
331 $ hg cat -r $H2~5 target
327 Tainted file now super sanitized
332 Tainted file now super sanitized
328 $ hg cat -r $C2 target
333 $ hg cat -r $C2 target
329 $ hg cat -r $C1 target
334 $ hg cat -r $C1 target
330 $ hg cat -r 0 target
335 $ hg cat -r 0 target
331 Initially untainted file
336 Initially untainted file
332 $ hg verify
337 $ hg verify
333 checking changesets
338 checking changesets
334 checking manifests
339 checking manifests
335 crosschecking files in changesets and manifests
340 crosschecking files in changesets and manifests
336 checking files
341 checking files
337 2 files, 12 changesets, 13 total revisions
342 2 files, 12 changesets, 13 total revisions
338
343
339 Repo cloned before tainted content introduced can pull censored nodes
344 Repo cloned before tainted content introduced can pull censored nodes
340
345
341 $ cd ../rpull
346 $ cd ../rpull
342 $ hg cat -r tip target
347 $ hg cat -r tip target
343 Initially untainted file
348 Initially untainted file
344 $ hg verify
349 $ hg verify
345 checking changesets
350 checking changesets
346 checking manifests
351 checking manifests
347 crosschecking files in changesets and manifests
352 crosschecking files in changesets and manifests
348 checking files
353 checking files
349 2 files, 1 changesets, 2 total revisions
354 2 files, 1 changesets, 2 total revisions
350 $ hg pull -r $H1 -r $H2
355 $ hg pull -r $H1 -r $H2
351 pulling from $TESTTMP/r (glob)
356 pulling from $TESTTMP/r (glob)
352 searching for changes
357 searching for changes
353 adding changesets
358 adding changesets
354 adding manifests
359 adding manifests
355 adding file changes
360 adding file changes
356 added 11 changesets with 11 changes to 2 files (+1 heads)
361 added 11 changesets with 11 changes to 2 files (+1 heads)
357 (run 'hg heads' to see heads, 'hg merge' to merge)
362 (run 'hg heads' to see heads, 'hg merge' to merge)
358 $ hg update 4
363 $ hg update 4
359 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
364 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
360 $ cat target
365 $ cat target
361 Tainted file now super sanitized
366 Tainted file now super sanitized
362 $ hg cat -r $H1 target
367 $ hg cat -r $H1 target
363 advanced head H1
368 advanced head H1
364 $ hg cat -r $H2~5 target
369 $ hg cat -r $H2~5 target
365 Tainted file now super sanitized
370 Tainted file now super sanitized
366 $ hg cat -r $C2 target
371 $ hg cat -r $C2 target
367 $ hg cat -r $C1 target
372 $ hg cat -r $C1 target
368 $ hg cat -r 0 target
373 $ hg cat -r 0 target
369 Initially untainted file
374 Initially untainted file
370 $ hg verify
375 $ hg verify
371 checking changesets
376 checking changesets
372 checking manifests
377 checking manifests
373 crosschecking files in changesets and manifests
378 crosschecking files in changesets and manifests
374 checking files
379 checking files
375 2 files, 12 changesets, 13 total revisions
380 2 files, 12 changesets, 13 total revisions
376
381
377 Censored nodes can be pushed if they censor previously unexchanged nodes
382 Censored nodes can be pushed if they censor previously unexchanged nodes
378
383
379 $ echo 'Passwords: hunter2hunter2' > target
384 $ echo 'Passwords: hunter2hunter2' > target
380 $ hg ci -m 're-add password from clone' target
385 $ hg ci -m 're-add password from clone' target
381 created new head
386 created new head
382 $ H3=`hg id --debug -i`
387 $ H3=`hg id --debug -i`
383 $ REV=$H3
388 $ REV=$H3
384 $ echo 'Re-sanitized; nothing to see here' > target
389 $ echo 'Re-sanitized; nothing to see here' > target
385 $ hg ci -m 're-sanitized' target
390 $ hg ci -m 're-sanitized' target
386 $ H2=`hg id --debug -i`
391 $ H2=`hg id --debug -i`
387 $ CLEANREV=$H2
392 $ CLEANREV=$H2
388 $ hg cat -r $REV target
393 $ hg cat -r $REV target
389 Passwords: hunter2hunter2
394 Passwords: hunter2hunter2
390 $ hg censor -r $REV target
395 $ hg censor -r $REV target
391 $ hg cat -r $REV target
396 $ hg cat -r $REV target
392 $ hg cat -r $CLEANREV target
397 $ hg cat -r $CLEANREV target
393 Re-sanitized; nothing to see here
398 Re-sanitized; nothing to see here
394 $ hg push -f -r $H2
399 $ hg push -f -r $H2
395 pushing to $TESTTMP/r (glob)
400 pushing to $TESTTMP/r (glob)
396 searching for changes
401 searching for changes
397 adding changesets
402 adding changesets
398 adding manifests
403 adding manifests
399 adding file changes
404 adding file changes
400 added 2 changesets with 2 changes to 1 files (+1 heads)
405 added 2 changesets with 2 changes to 1 files (+1 heads)
401
406
402 $ cd ../r
407 $ cd ../r
403 $ hg cat -r $REV target
408 $ hg cat -r $REV target
404 $ hg cat -r $CLEANREV target
409 $ hg cat -r $CLEANREV target
405 Re-sanitized; nothing to see here
410 Re-sanitized; nothing to see here
406 $ hg update $CLEANREV
411 $ hg update $CLEANREV
407 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
412 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
408 $ cat target
413 $ cat target
409 Re-sanitized; nothing to see here
414 Re-sanitized; nothing to see here
410
415
411 Censored nodes can be bundled up and unbundled in another repo
416 Censored nodes can be bundled up and unbundled in another repo
412
417
413 $ hg bundle --base 0 ../pwbundle
418 $ hg bundle --base 0 ../pwbundle
414 13 changesets found
419 13 changesets found
415 $ cd ../rclone
420 $ cd ../rclone
416 $ hg unbundle ../pwbundle
421 $ hg unbundle ../pwbundle
417 adding changesets
422 adding changesets
418 adding manifests
423 adding manifests
419 adding file changes
424 adding file changes
420 added 2 changesets with 2 changes to 2 files (+1 heads)
425 added 2 changesets with 2 changes to 2 files (+1 heads)
421 (run 'hg heads .' to see heads, 'hg merge' to merge)
426 (run 'hg heads .' to see heads, 'hg merge' to merge)
422 $ hg cat -r $REV target
427 $ hg cat -r $REV target
423 $ hg cat -r $CLEANREV target
428 $ hg cat -r $CLEANREV target
424 Re-sanitized; nothing to see here
429 Re-sanitized; nothing to see here
425 $ hg update $CLEANREV
430 $ hg update $CLEANREV
426 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
431 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
427 $ cat target
432 $ cat target
428 Re-sanitized; nothing to see here
433 Re-sanitized; nothing to see here
429 $ hg verify
434 $ hg verify
430 checking changesets
435 checking changesets
431 checking manifests
436 checking manifests
432 crosschecking files in changesets and manifests
437 crosschecking files in changesets and manifests
433 checking files
438 checking files
434 2 files, 14 changesets, 15 total revisions
439 2 files, 14 changesets, 15 total revisions
435
440
436 Censored nodes can be imported on top of censored nodes, consecutively
441 Censored nodes can be imported on top of censored nodes, consecutively
437
442
438 $ hg init ../rimport
443 $ hg init ../rimport
439 $ hg bundle --base 1 ../rimport/splitbundle
444 $ hg bundle --base 1 ../rimport/splitbundle
440 12 changesets found
445 12 changesets found
441 $ cd ../rimport
446 $ cd ../rimport
442 $ hg pull -r $H1 -r $H2 ../r
447 $ hg pull -r $H1 -r $H2 ../r
443 pulling from ../r
448 pulling from ../r
444 adding changesets
449 adding changesets
445 adding manifests
450 adding manifests
446 adding file changes
451 adding file changes
447 added 8 changesets with 10 changes to 2 files (+1 heads)
452 added 8 changesets with 10 changes to 2 files (+1 heads)
448 (run 'hg heads' to see heads, 'hg merge' to merge)
453 (run 'hg heads' to see heads, 'hg merge' to merge)
449 $ hg unbundle splitbundle
454 $ hg unbundle splitbundle
450 adding changesets
455 adding changesets
451 adding manifests
456 adding manifests
452 adding file changes
457 adding file changes
453 added 6 changesets with 5 changes to 2 files (+1 heads)
458 added 6 changesets with 5 changes to 2 files (+1 heads)
454 (run 'hg heads .' to see heads, 'hg merge' to merge)
459 (run 'hg heads .' to see heads, 'hg merge' to merge)
455 $ hg update $H2
460 $ hg update $H2
456 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
461 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
457 $ cat target
462 $ cat target
458 Re-sanitized; nothing to see here
463 Re-sanitized; nothing to see here
459 $ hg verify
464 $ hg verify
460 checking changesets
465 checking changesets
461 checking manifests
466 checking manifests
462 crosschecking files in changesets and manifests
467 crosschecking files in changesets and manifests
463 checking files
468 checking files
464 2 files, 14 changesets, 15 total revisions
469 2 files, 14 changesets, 15 total revisions
465 $ cd ../r
470 $ cd ../r
466
471
467 Can import bundle where first revision of a file is censored
472 Can import bundle where first revision of a file is censored
468
473
469 $ hg init ../rinit
474 $ hg init ../rinit
470 $ hg censor -r 0 target
475 $ hg censor -r 0 target
471 $ hg bundle -r 0 --base null ../rinit/initbundle
476 $ hg bundle -r 0 --base null ../rinit/initbundle
472 1 changesets found
477 1 changesets found
473 $ cd ../rinit
478 $ cd ../rinit
474 $ hg unbundle initbundle
479 $ hg unbundle initbundle
475 adding changesets
480 adding changesets
476 adding manifests
481 adding manifests
477 adding file changes
482 adding file changes
478 added 1 changesets with 2 changes to 2 files
483 added 1 changesets with 2 changes to 2 files
479 (run 'hg update' to get a working copy)
484 (run 'hg update' to get a working copy)
480 $ hg cat -r 0 target
485 $ hg cat -r 0 target
General Comments 0
You need to be logged in to leave comments. Login now