use Python instead of sed for secret substitution and use escapeShellArg

#720
This commit is contained in:
Dmitry 2026-06-05 17:07:00 +01:00 committed by GitHub
parent 669d4bf1b7
commit 1b89d47651
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,7 +1,12 @@
{ pkgs, lib }:
let
inherit (builtins) isAttrs hasAttr;
inherit (lib) any concatMapStringsSep concatStringsSep;
inherit (lib)
any
concatMapStringsSep
concatStringsSep
escapeShellArg
;
shb = rec {
# Replace secrets in a file.
# - userConfig is an attrset that will produce a config file.
@ -76,11 +81,41 @@ let
pattern: "cat ${pattern.source} > /dev/null"
) replacements;
sedPatterns = concatMapStringsSep " " (pattern: "-e \"s|${pattern.name}|${pattern.value}|\"") (
map genReplacement replacements
);
generatedReplacements = map genReplacement replacements;
sedCmd = if replacements == [ ] then "cat" else "${pkgs.gnused}/bin/sed ${sedPatterns}";
replaceScript = pkgs.writers.writePython3 "replace-secret" { } ''
import argparse
import pathlib
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser()
parser.add_argument("--file", required=True, type=pathlib.Path)
parser.add_argument("--marker", required=True)
parser.add_argument("--replacement", required=True)
return parser.parse_args()
args = parse_args()
content = args.file.read_text()
args.file.write_text(content.replace(args.marker, args.replacement))
'';
replaceCommands = concatMapStringsSep "\n" (pattern: ''
${replaceScript} \
--file ${escapeShellArg resultPath} \
--marker ${escapeShellArg pattern.name} \
--replacement "${pattern.value}"
'') generatedReplacements;
replaceCmd =
if replacements == [ ] then
"cat ${escapeShellArg templatePath} > ${escapeShellArg resultPath}"
else
''
cat ${escapeShellArg templatePath} > ${escapeShellArg resultPath}
${replaceCommands}
'';
in
''
set -euo pipefail
@ -96,7 +131,7 @@ let
chown ${user} ${resultPath}
'')
+ ''
${sedCmd} ${templatePath} > ${resultPath}
${replaceCmd}
chmod ${permissions} ${resultPath}
'';