Ignore encrypted files (#69)

Append the contents of .config/yadm/encrypt to the repo's git ignore
list. This is to help prevent accidentally committing unencrypted
sensitive data.
This commit is contained in:
Tim Byrne 2019-10-15 07:17:38 -05:00
parent f3249e00b5
commit 0c9468c9b5
No known key found for this signature in database
GPG Key ID: 14DB4FC2465A4B12
6 changed files with 159 additions and 1 deletions

View File

@ -101,6 +101,7 @@ def supported_configs():
'local.user',
'yadm.alt-copy',
'yadm.auto-alt',
'yadm.auto-exclude',
'yadm.auto-perms',
'yadm.auto-private-dirs',
'yadm.git-program',

View File

@ -372,6 +372,29 @@ def test_offer_to_add(runner, yadm_y, paths, encrypt_targets, untracked):
assert f'AM {worktree_archive.basename}' in run.out
def test_encrypt_added_to_exclude(runner, yadm_y, paths):
"""Confirm that .config/yadm/encrypt is added to exclude"""
expect = [
('passphrase:', PASSPHRASE),
('passphrase:', PASSPHRASE),
]
exclude_file = paths.repo.join('info/exclude')
paths.encrypt.write('test-encrypt-data\n')
exclude_file.write('original-data', ensure=True)
run = runner(
yadm_y('encrypt'),
expect=expect,
)
assert 'test-encrypt-data' in paths.repo.join('info/exclude').read()
assert 'original-data' in paths.repo.join('info/exclude').read()
assert run.success
assert run.err == ''
def encrypted_data_valid(runner, encrypted, expected):
"""Verify encrypted data matches expectations"""
run = runner([

View File

@ -27,7 +27,7 @@ def test_introspect_category(
expected = []
if name == 'commands':
expected = supported_commands
elif name == 'config':
elif name == 'configs':
expected = supported_configs
elif name == 'switches':
expected = supported_switches

View File

@ -0,0 +1,66 @@
"""Unit tests: exclude_encrypted"""
import pytest
@pytest.mark.parametrize(
'exclude', ['missing', 'outdated', 'up-to-date'])
@pytest.mark.parametrize(
'encrypt_exists', [True, False], ids=['encrypt', 'no-encrypt'])
@pytest.mark.parametrize(
'auto_exclude', [True, False], ids=['enabled', 'disabled'])
def test_exclude_encrypted(
runner, tmpdir, yadm, encrypt_exists, auto_exclude, exclude):
"""Test exclude_encrypted()"""
header = (
"# yadm-auto-excludes\n"
"# This section is managed by yadm.\n"
"# Any edits below will be lost.\n"
)
config_function = 'function config() { echo "false";}'
if auto_exclude:
config_function = 'function config() { return; }'
encrypt_file = tmpdir.join('encrypt_file')
repo_dir = tmpdir.join('repodir')
exclude_file = repo_dir.join('info/exclude')
if encrypt_exists:
encrypt_file.write('test-encrypt-data\n', ensure=True)
if exclude == 'outdated':
exclude_file.write(
f'original-exclude\n{header}outdated\n', ensure=True)
elif exclude == 'up-to-date':
exclude_file.write(
f'original-exclude\n{header}test-encrypt-data\n', ensure=True)
script = f"""
YADM_TEST=1 source {yadm}
{config_function}
DEBUG=1
YADM_ENCRYPT="{encrypt_file}"
YADM_REPO="{repo_dir}"
exclude_encrypted
"""
run = runner(command=['bash'], inp=script)
assert run.success
assert run.err == ''
if auto_exclude:
if encrypt_exists:
assert exclude_file.exists()
if exclude == 'missing':
assert exclude_file.read() == f'{header}test-encrypt-data\n'
else:
assert exclude_file.read() == (
'original-exclude\n'
f'{header}test-encrypt-data\n')
if exclude != 'up-to-date':
assert f'Updating {exclude_file}' in run.out
else:
assert run.out == ''
else:
assert run.out == ''
else:
assert run.out == ''

51
yadm
View File

@ -804,6 +804,7 @@ function encrypt() {
require_gpg
require_encrypt
exclude_encrypted
parse_encrypt
cd_work "Encryption" || return
@ -986,6 +987,7 @@ local.os
local.user
yadm.alt-copy
yadm.auto-alt
yadm.auto-exclude
yadm.auto-perms
yadm.auto-private-dirs
yadm.git-program
@ -1069,6 +1071,55 @@ function version() {
# ****** Utility Functions ******
function exclude_encrypted() {
auto_exclude=$(config --bool yadm.auto-exclude)
[ "$auto_exclude" == "false" ] && return 0
exclude_path="${YADM_REPO}/info/exclude"
newline=$'\n'
exclude_flag="# yadm-auto-excludes"
exclude_header="${exclude_flag}${newline}"
exclude_header="${exclude_header}# This section is managed by yadm."
exclude_header="${exclude_header}${newline}"
exclude_header="${exclude_header}# Any edits below will be lost."
exclude_header="${exclude_header}${newline}"
# do nothing if there is no YADM_ENCRYPT
[ -e "$YADM_ENCRYPT" ] || return 0
# read encrypt
encrypt_data=""
while IFS='' read -r line || [ -n "$line" ]; do
encrypt_data="${encrypt_data}${line}${newline}"
done < "$YADM_ENCRYPT"
# read info/exclude
unmanaged=""
managed=""
if [ -e "$exclude_path" ]; then
flag_seen=0
while IFS='' read -r line || [ -n "$line" ]; do
[ "$line" = "$exclude_flag" ] && flag_seen=1
if [ "$flag_seen" -eq 0 ]; then
unmanaged="${unmanaged}${line}${newline}"
else
managed="${managed}${line}${newline}"
fi
done < "$exclude_path"
fi
if [ "${exclude_header}${encrypt_data}" != "$managed" ]; then
basedir=${exclude_path%/*}
[ -e "$basedir" ] || mkdir -p "$basedir" # assert path
debug "Updating ${exclude_path}"
printf "%s" "${unmanaged}${exclude_header}${encrypt_data}" > "$exclude_path"
fi
return 0
}
function is_valid_branch_name() {
# Git branches do not allow:
# * path component that begins with "."

17
yadm.1
View File

@ -347,6 +347,11 @@ Disable the automatic linking described in the section ALTERNATES. If disabled,
you may still run "yadm alt" manually to create the alternate links. This
feature is enabled by default.
.TP
.B yadm.auto-exclude
Disable the automatic exclusion of patterns defined in
.IR $HOME/.config/yadm/encrypt .
This feature is enabled by default.
.TP
.B yadm.auto-perms
Disable the automatic permission changes described in the section PERMISSIONS.
If disabled, you may still run
@ -674,6 +679,18 @@ configuration.
It is recommended that you use a private repository when keeping confidential
files, even though they are encrypted.
Patterns found in
.I $HOME/.config/yadm/encrypt
are automatically added to the repository's
.I info/exclude
file every time
.B yadm encrypt
is run.
This is to prevent accidentally committing sensitive data to the repository.
This can be disabled using the
.I yadm.auto-exclude
configuration.
.SH PERMISSIONS
When files are checked out of a Git repository, their initial permissions are