cmds.secrets.FilesContext: Re-shuffle attrs precedence
_compile_one_template_file() re-parses the template's own conf line and, when present, discards the attrs that compile_template_file() merged from the command-line defaults, the template, the .jw-secret-file, and the .jw-secret. The merge already orders the sources so that later non-empty fields override earlier ones; discarding it inverts the order and lets the template's line override the one the operator placed in the .jw-secret. Strip the template's conf line from the content and apply the merged attrs instead, so the .jw-secret conf line takes the last word again, as the compiler did before the rewrite. The integration test gains a target whose template and secret both carry a conf line. Assisted-by: unsloth/Qwen3.8-27B-GGUF:Q4_K_M with pi.dev v1.4.0 Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
parent
9e7c73bbdf
commit
ea45cb1fed
1 changed files with 41 additions and 12 deletions
|
|
@ -190,6 +190,11 @@ def main() -> None:
|
|||
# extract it, and must not leave an empty file behind
|
||||
with open(target + '/etc/baz.conf.jw-tmpl', 'w') as f:
|
||||
f.write('x=X\n')
|
||||
# -- corge has a conf line in the template and one in the
|
||||
# secret: the secret's line takes precedence
|
||||
with open(target + '/etc/corge.conf.jw-tmpl', 'w') as f:
|
||||
f.write(f'# conf: owner={USER}, group={GROUP}, mode=640\n'
|
||||
'key=KEY\n')
|
||||
# -- qux references a macro that has no store entry: the
|
||||
# compile must fail rather than emit a literal macro
|
||||
with open(target + '/etc/qux.conf.jw-tmpl', 'w') as f:
|
||||
|
|
@ -208,9 +213,11 @@ def main() -> None:
|
|||
foo_secret = target + '/etc/foo.conf.jw-secret'
|
||||
bar_secret = target + '/etc/bar.conf.jw-secret'
|
||||
baz_secret = target + '/etc/baz.conf.jw-secret'
|
||||
corge_secret = target + '/etc/corge.conf.jw-secret'
|
||||
foo_out = target + '/etc/foo.conf'
|
||||
bar_out = target + '/etc/bar.conf'
|
||||
baz_out = target + '/etc/baz.conf'
|
||||
corge_out = target + '/etc/corge.conf'
|
||||
|
||||
# -- The GPG-encrypted tar store in canonical layout. Member
|
||||
# names are <prefix>/<target path without leading slash>
|
||||
|
|
@ -230,6 +237,8 @@ def main() -> None:
|
|||
'HOSTNAME=jannet\nTOKEN=host-token\n',
|
||||
f'default/{trel}/etc/bar.conf.jw-secret': \
|
||||
'PLAIN=plain-value\n',
|
||||
f'default/{trel}/etc/corge.conf.jw-secret': \
|
||||
'KEY=corge-value\n',
|
||||
# A member that is not a secret of the fixture
|
||||
# package: install must not extract it
|
||||
f'default/{trel}/etc/cert.pem': 'decoy certificate\n',
|
||||
|
|
@ -242,7 +251,13 @@ def main() -> None:
|
|||
distro = FakeDistro(
|
||||
Local('local://' + HOST),
|
||||
{
|
||||
PKG: [foo_tmpl, bar_tmpl, baz_tmpl, target + '/etc/readme.txt'],
|
||||
PKG: [
|
||||
foo_tmpl,
|
||||
bar_tmpl,
|
||||
baz_tmpl,
|
||||
target + '/etc/corge.conf.jw-tmpl',
|
||||
target + '/etc/readme.txt',
|
||||
],
|
||||
PKG2: [qux_tmpl],
|
||||
},
|
||||
)
|
||||
|
|
@ -250,7 +265,8 @@ def main() -> None:
|
|||
# -- list-templates: only the .jw-tmpl files of the package
|
||||
|
||||
out, _ = run_cli(distro, ['secrets', 'list-templates', PKG])
|
||||
assert out == [foo_tmpl, bar_tmpl, baz_tmpl], out
|
||||
assert out == [foo_tmpl, bar_tmpl, baz_tmpl,
|
||||
target + '/etc/corge.conf.jw-tmpl'], out
|
||||
|
||||
# -- list-secrets: nothing installed yet
|
||||
|
||||
|
|
@ -258,7 +274,7 @@ def main() -> None:
|
|||
assert out == [], out
|
||||
|
||||
out, _ = run_cli(distro, ['secrets', 'list-secrets', '--all', PKG])
|
||||
assert out == [foo_secret, bar_secret, baz_secret], out
|
||||
assert out == [foo_secret, bar_secret, baz_secret, corge_secret], out
|
||||
|
||||
# -- list-compilation-output: nothing compiled yet
|
||||
|
||||
|
|
@ -266,7 +282,7 @@ def main() -> None:
|
|||
assert out == [], out
|
||||
|
||||
out, _ = run_cli(distro, ['secrets', 'list-compilation-output', '--all', PKG])
|
||||
assert out == [foo_out, bar_out, baz_out], out
|
||||
assert out == [foo_out, bar_out, baz_out, corge_out], out
|
||||
|
||||
# -- install: decrypt the tarball, keep the host-specific entry
|
||||
# over the default one, extract only the needed secrets
|
||||
|
|
@ -286,7 +302,7 @@ def main() -> None:
|
|||
assert stat.S_IMODE(os.stat(foo_secret).st_mode) == 0o400
|
||||
|
||||
out, _ = run_cli(distro, ['secrets', 'list-secrets', PKG])
|
||||
assert out == [foo_secret, bar_secret], out
|
||||
assert out == [foo_secret, bar_secret, corge_secret], out
|
||||
|
||||
if HAVE_TARGPG:
|
||||
# -- a rooted targpg:// URI is rejected: install addresses
|
||||
|
|
@ -315,11 +331,16 @@ def main() -> None:
|
|||
assert stat.S_IMODE(os.stat(foo_secret).st_mode) == 0o400
|
||||
|
||||
# -- The file attributes can also be specified atop the
|
||||
# .jw-secret; bar takes its mode from there
|
||||
# .jw-secret; bar takes its mode from there. corge gets a
|
||||
# line as well: it takes precedence over the template's
|
||||
os.unlink(bar_secret)
|
||||
with open(bar_secret, 'w') as f:
|
||||
f.write(f'# conf: owner={USER}, group={GROUP}, mode=640\n')
|
||||
f.write('PLAIN=plain-value\n')
|
||||
os.unlink(corge_secret)
|
||||
with open(corge_secret, 'w') as f:
|
||||
f.write('# conf: mode=400\n')
|
||||
f.write('KEY=corge-value\n')
|
||||
|
||||
# -- compile-templates: substitute the keys, apply the
|
||||
# metadata; the conf lines win over the --mode default
|
||||
|
|
@ -346,6 +367,12 @@ def main() -> None:
|
|||
assert (st.st_uid, stat.S_IMODE(st.st_mode)) == (os.getuid(), 0o640), st
|
||||
with open(bar_out) as f:
|
||||
assert f.read() == 'plain=plain-value\n'
|
||||
# -- the secret's conf line takes precedence over the
|
||||
# template's: corge comes out 0400, not the template's 640
|
||||
st = os.stat(corge_out)
|
||||
assert (st.st_uid, stat.S_IMODE(st.st_mode)) == (os.getuid(), 0o400), st
|
||||
with open(corge_out) as f:
|
||||
assert f.read() == 'key=corge-value\n'
|
||||
|
||||
# -- compile-templates is idempotent
|
||||
|
||||
|
|
@ -401,7 +428,7 @@ def main() -> None:
|
|||
assert not os.path.exists(qux_out)
|
||||
|
||||
out, _ = run_cli(distro, ['secrets', 'list-compilation-output', PKG])
|
||||
assert out == [foo_out, bar_out, baz_out], out
|
||||
assert out == [foo_out, bar_out, baz_out, corge_out], out
|
||||
|
||||
# -- rm-compilation-output: drop the compiled files
|
||||
|
||||
|
|
@ -410,6 +437,7 @@ def main() -> None:
|
|||
assert not os.path.exists(foo_out)
|
||||
assert not os.path.exists(bar_out)
|
||||
assert not os.path.exists(baz_out)
|
||||
assert not os.path.exists(corge_out)
|
||||
|
||||
print('All secrets command tests passed')
|
||||
finally:
|
||||
|
|
|
|||
Loading…
Reference in a new issue