Skip to content

Commit

Permalink
Ignore encrypted files (yadm-dev#69)
Browse files Browse the repository at this point in the history
Append the contents of .config/yadm/encrypt to the repo's git ignore
list. This is to help prevent accidentally committing unencrypted
sensitive data.
  • Loading branch information
TheLocehiliosan committed Oct 17, 2019
1 parent f3249e0 commit 0c9468c
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 1 deletion.
1 change: 1 addition & 0 deletions test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
23 changes: 23 additions & 0 deletions test/test_encryption.py
Original file line number Diff line number Diff line change
Expand Up @@ -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([
Expand Down
2 changes: 1 addition & 1 deletion test/test_introspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
66 changes: 66 additions & 0 deletions test/test_unit_exclude_encrypted.py
Original file line number Diff line number Diff line change
@@ -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 changes: 51 additions & 0 deletions yadm
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,7 @@ function encrypt() {

require_gpg
require_encrypt
exclude_encrypted
parse_encrypt

cd_work "Encryption" || return
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 "."
Expand Down
17 changes: 17 additions & 0 deletions yadm.1
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 0c9468c

Please sign in to comment.