Fix: Harden installer provenance boundary
This commit is contained in:
@@ -6,15 +6,27 @@
|
|||||||
|
|
||||||
declare -gA INSTALLER_PROVENANCE=()
|
declare -gA INSTALLER_PROVENANCE=()
|
||||||
|
|
||||||
|
_primary_key_fingerprints() {
|
||||||
|
gpg --batch --with-colons --import-options show-only --import "$1" 2>/dev/null \
|
||||||
|
| awk -F: '$1 == "pub" { primary = 1; next } primary && $1 == "fpr" { print $10; primary = 0 }'
|
||||||
|
}
|
||||||
|
|
||||||
key_fingerprint_matches() {
|
key_fingerprint_matches() {
|
||||||
local file="$1" expected="$2" actual
|
local file="$1" expected="$2"
|
||||||
actual="$(gpg --batch --with-colons --import-options show-only --import "$file" 2>/dev/null \
|
local -a primary_fingerprints=()
|
||||||
| awk -F: '$1 == "fpr" { print $10; exit }')"
|
mapfile -t primary_fingerprints < <(_primary_key_fingerprints "$file")
|
||||||
[[ "$actual" == "$expected" ]]
|
[[ ${#primary_fingerprints[@]} -eq 1 && "${primary_fingerprints[0]}" == "$expected" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
_key_has_one_primary() {
|
||||||
|
local -a primary_fingerprints=()
|
||||||
|
mapfile -t primary_fingerprints < <(_primary_key_fingerprints "$1")
|
||||||
|
[[ ${#primary_fingerprints[@]} -eq 1 ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_detached_signature() {
|
verify_detached_signature() {
|
||||||
local key="$1" signature="$2" content="$3" home
|
local key="$1" signature="$2" content="$3" home
|
||||||
|
_key_has_one_primary "$key" || return 1
|
||||||
home="$(mktemp -d)" || return 1
|
home="$(mktemp -d)" || return 1
|
||||||
chmod 700 "$home"
|
chmod 700 "$home"
|
||||||
GNUPGHOME="$home" gpg --batch --quiet --import "$key" >/dev/null 2>&1 \
|
GNUPGHOME="$home" gpg --batch --quiet --import "$key" >/dev/null 2>&1 \
|
||||||
@@ -25,18 +37,22 @@ verify_detached_signature() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
download_sha256() {
|
download_sha256() {
|
||||||
local url="$1" expected="$2" max_bytes="$3" destination="$4" actual
|
local url="$1" expected="$2" max_bytes="$3" destination="$4" actual directory filename
|
||||||
|
|
||||||
[[ "$expected" =~ ^[0-9a-f]{64}$ ]] || return 1
|
[[ "$expected" =~ ^[0-9a-f]{64}$ ]] || return 1
|
||||||
actual="$expected"
|
actual="$expected"
|
||||||
|
|
||||||
local part="${destination}.part"
|
directory="$(dirname -- "$destination")"
|
||||||
|
filename="$(basename -- "$destination")"
|
||||||
(
|
(
|
||||||
trap 'rm -f -- "$part"' EXIT
|
local part=""
|
||||||
|
trap '[[ -z "$part" ]] || rm -f -- "$part"' EXIT
|
||||||
trap 'exit 130' INT
|
trap 'exit 130' INT
|
||||||
trap 'exit 143' TERM
|
trap 'exit 143' TERM
|
||||||
[[ "$max_bytes" =~ ^[1-9][0-9]*$ ]] || exit 1
|
[[ "$max_bytes" =~ ^[1-9][0-9]*$ ]] || exit 1
|
||||||
[[ -n "$destination" && -d "$(dirname "$destination")" ]] || exit 1
|
[[ -n "$destination" && -d "$directory" ]] || exit 1
|
||||||
|
umask 077
|
||||||
|
part="$(mktemp "$directory/.${filename}.part.XXXXXX")" || exit 1
|
||||||
curl --fail --location --connect-timeout 10 --max-time 600 \
|
curl --fail --location --connect-timeout 10 --max-time 600 \
|
||||||
--max-filesize "$max_bytes" --output "$part" "$url" \
|
--max-filesize "$max_bytes" --output "$part" "$url" \
|
||||||
|| exit 1
|
|| exit 1
|
||||||
|
|||||||
@@ -1 +1,4 @@
|
|||||||
291bd319ae85488101e908e37fc0fa1b0da1429ba27e10d2b391cb3f60dd44ea tiny-artifact
|
291bd319ae85488101e908e37fc0fa1b0da1429ba27e10d2b391cb3f60dd44ea tiny-artifact
|
||||||
|
5043218f6d8ecdb2ba78665116f74e7f53ce29d164117a0b6cb0f946811d3455 tiny-artifact-tampered
|
||||||
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa metadata-only-1
|
||||||
|
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb metadata-only-2
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
-----BEGIN PGP SIGNATURE-----
|
-----BEGIN PGP SIGNATURE-----
|
||||||
|
|
||||||
iQEzBAABCgAdFiEEYBb/GMrimM42SO4jJeAfdl4e+foFAmqQBJoACgkQJeAfdl4e
|
iQEzBAABCgAdFiEEYBb/GMrimM42SO4jJeAfdl4e+foFAmqQCQ8ACgkQJeAfdl4e
|
||||||
+foW9Qf/QLO0N5vVdG3Fi9ql6SE3dZItZtrJy4jFVPDEVEZJK4PoT9iRE/RQwqsU
|
+fqUiQgAgPaA6eTS3ag1YMLhT4r3JVpL40HgKTLBfTgRjsc/AVwG9aV9BMYMHwGT
|
||||||
7y86B1x0JmCoxVRigLD75gz8IYb8SzchbTrUQRB/l0FBjNZaeAX1O+E8GZIsK9Kf
|
3pCzs1ULlF1Vw9mFODt6YPBJeuq2hdI26MVJ1YWo6YkiCqzrsu3LycZCvBezC8hi
|
||||||
KljmaIiG8vrwGilCxZnJPGv80mMpW9LETgF9be2L8bZff/UDwEZfOenYIgievUJW
|
6/4ZW/j/7tMeVr2Oqw4Vv5quvLQ2DO/ZE3vMtKJ+sRvVHnczlQJrrKpzJ15pVv5l
|
||||||
cuNe41jzOd0kYuOggnxPsOqxfd+ludpwjOO/z2j2TV8J4H7JHzoRzG8100J+DYoY
|
a5OMFfTeCeOXOJ145lDlEdvmjaJUPUp6cw248azhEAwu24a0u4iqIb59nz/IhLiD
|
||||||
ud9GyH1AtgGlQ3XALb4UotE3Btf8GiZ1Mg/igxZqvjCJhrfOiaeziKi4a80fhv9z
|
/rkUQrc2CGwBEUSwDDMLELLMTHc/Ivm6xLQOI+TbT53+1IupyUu5gquRM7pdKGw7
|
||||||
j1KFafXj9lc69vBgayepHF8BH6bocQ==
|
SYTz3awbjyEzFLt60AnPsSWNyo5N6A==
|
||||||
=nTYb
|
=MJqv
|
||||||
-----END PGP SIGNATURE-----
|
-----END PGP SIGNATURE-----
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
tampered artifact
|
tiny artifacT
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
-----BEGIN PGP SIGNATURE-----
|
||||||
|
|
||||||
|
iQEzBAABCgAdFiEE8NsXb+IUusO1vCd8zouSo0jXorAFAmqQCQ8ACgkQzouSo0jX
|
||||||
|
orCpQAf+PB6BsCoq/Sp4LShSNTlZkDWS7p641A29OgAtr6QYUphMsI+gY6tKK0zr
|
||||||
|
zmDzs4MyZaSy/yx9jEdPyyVWLFREk0u/x6YpQwj8KGbtuTt/hBQgkshDZZeVdGLr
|
||||||
|
x11bkZgOENjzRS/NnKiziwoVVwaZm36WrsCef6Q26sbxCnYF2nWlGNtP9SKnhxSV
|
||||||
|
/FYXi/wW41p8iZqIb0SFRoMGMsazV5i9XOjTLx4dEiMaeGvnNdZoMDGIO8in7mJG
|
||||||
|
pkYro8coAGwjyC48VZmCPFG0TPqVhc0LEYKcI4M1OyEX38xQqaoRm5k9sOswfyDF
|
||||||
|
iTFTwna0Zb1nurK/28/WfUHqLEIlQw==
|
||||||
|
=PvFe
|
||||||
|
-----END PGP SIGNATURE-----
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
7avu2wMAAAAAAHBhbmFtYS1wcm92ZW5hbmNlLWZpeHR1cmUtMS0xAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAAAAAAAAjq3oAQAAAAAAAAAIAAAQpAAA
|
||||||
|
AD4AAAAHAAAQlAAAABAAAAEMAAAABwAAAAAAAAE2AAABDQAAAAYAAAE2AAAAAQAAAREAAAAGAAAB
|
||||||
|
XwAAAAEAAAPoAAAABAAAAaAAAAABAAAD7AAAAAcAAAGkAAAAEAAAA+8AAAAEAAABtAAAAAEAAAPw
|
||||||
|
AAAABwAAAbgAAA7ciQEzBAABCgAdFiEE8NsXb+IUusO1vCd8zouSo0jXorAFAmqQCOUACgkQzouS
|
||||||
|
o0jXorAkrwf/diXYa/W3A1v8HNykf8NA2gmyNHVIm/AMGGZE1TC49eiMgj1+KpoznyImuP5bpGSC
|
||||||
|
fMeG0sMrRabG4eYJ7eXDNviVNDslet6ooNRlvRE0F4zQZERub1l4afHHuJuHWHi/J/UpWotOxQa0
|
||||||
|
akXy7/fE4Easoy8ddzdx5IYS9SLDiKMxuVhp3oqkiC1QyX6gV3cd+iF128IJMhhA2UMnA7nRX1vH
|
||||||
|
sDK1WNQub3GeS9svYVCXfSy4NTIbsP6zynLRFp3nEKfRkVWILnrGGHL7ZBNH4aaURUN57lu83Cv+
|
||||||
|
DOB9LlS2z704feRKJRWj+wLmOZvx37426Tr7ZllLHvs5xvkH0DM1NTg5MDBmNWUwM2YwNzFhNjM1
|
||||||
|
ZDg1ZjgxODI3NTA3YjdiMWQ1MDYAMjQ4ZTQ3YzFiNjhlYjM5NDgxMWFmNWJhOGZlNGNiZTEzYmUy
|
||||||
|
MGM5N2I0MzM2MzM1MGRhOGE2MDY0ZWQ4YTk4ZgAAAAiZ9bUc5Ib0/pUFYQ1fQtgpwwAAASQAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAAAB////4AAAAAQAAAA
|
||||||
|
AI6t6AEAAAAAAAAAMwAABOEAAAA/AAAABwAABNEAAAAQAAAAZAAAAAgAAAAAAAAAAQAAA+gAAAAG
|
||||||
|
AAAAAgAAAAEAAAPpAAAABgAAABwAAAABAAAD6gAAAAYAAAAeAAAAAQAAA+wAAAAJAAAAIAAAAAEA
|
||||||
|
AAPtAAAACQAAAD8AAAABAAAD7gAAAAQAAABYAAAAAQAAA+8AAAAGAAAAXAAAAAEAAAPxAAAABAAA
|
||||||
|
AGgAAAABAAAD9gAAAAYAAABsAAAAAQAAA/gAAAAJAAAAcAAAAAEAAAP9AAAABgAAAHwAAAABAAAD
|
||||||
|
/gAAAAYAAACCAAAAAQAABAQAAAAEAAAAjAAAAAEAAAQGAAAAAwAAAJAAAAABAAAECQAAAAMAAACS
|
||||||
|
AAAAAQAABAoAAAAEAAAAlAAAAAEAAAQLAAAACAAAAJgAAAABAAAEDAAAAAgAAADZAAAAAQAABA0A
|
||||||
|
AAAEAAAA3AAAAAEAAAQPAAAACAAAAOAAAAABAAAEEAAAAAgAAADlAAAAAQAABBQAAAAGAAAA6gAA
|
||||||
|
AAEAAAQVAAAABAAAARAAAAABAAAEFwAAAAgAAAEUAAAAAQAABBgAAAAEAAABMAAAAAQAAAQZAAAA
|
||||||
|
CAAAAUAAAAAEAAAEGgAAAAgAAAGlAAAABAAABCgAAAAGAAABxAAAAAEAAARHAAAABAAAAcwAAAAB
|
||||||
|
AAAESAAAAAQAAAHQAAAAAQAABEkAAAAIAAAB1AAAAAEAAARYAAAABAAAAdgAAAABAAAEWQAAAAgA
|
||||||
|
AAHcAAAAAQAABFwAAAAEAAAB4AAAAAEAAARdAAAACAAAAeQAAAABAAAEXgAAAAgAAAHwAAAAAQAA
|
||||||
|
BGIAAAAGAAACFgAAAAEAAARkAAAABgAABAUAAAABAAAEZQAAAAYAAAQKAAAAAQAABGYAAAAGAAAE
|
||||||
|
DwAAAAEAAARsAAAABgAABBIAAAABAAAEdAAAAAQAAAQsAAAAAQAABHUAAAAEAAAEMAAAAAEAAAR2
|
||||||
|
AAAACAAABDQAAAABAAATkwAAAAQAAARAAAAAAQAAE8YAAAAGAAAERAAAAAEAABPkAAAACAAABEoA
|
||||||
|
AAABAAAT5QAAAAQAAASMAAAAAQAAE+kAAAAIAAAEkAAAAAFDAHBhbmFtYS1wcm92ZW5hbmNlLWZp
|
||||||
|
eHR1cmUAMQAxAFBhbmFtYSBwcm92ZW5hbmNlIHRlc3QgZml4dHVyZQBBIHRlc3Qtb25seSBSUE0g
|
||||||
|
Zml4dHVyZS4AapAEmmRlc2t0b3AtZ2liAAAAAAhNSVQAVW5zcGVjaWZpZWQAbGludXgAbm9hcmNo
|
||||||
|
AAAAAAAAAAiBpAAAapAEmmU4MGI3MWNkMTRkM2NiZDY1ZjQxNzNhYmNiZmNmMDFhNTQ1ZGJjYTMy
|
||||||
|
YTcyZDU3NTEwOGI1NTNhNjQ4Y2M5NmYAAAAAAAAAAHJvb3QAcm9vdABwYW5hbWEtcHJvdmVuYW5j
|
||||||
|
ZS1maXh0dXJlLTEtMS5zcmMucnBtAP////9wYW5hbWEtcHJvdmVuYW5jZS1maXh0dXJlAAAAAQAA
|
||||||
|
CgEAAAoBAAAKAQAACnJwbWxpYihDb21wcmVzc2VkRmlsZU5hbWVzKQBycG1saWIoRmlsZURpZ2Vz
|
||||||
|
dHMpAHJwbWxpYihQYXlsb2FkRmlsZXNIYXZlUHJlZml4KQBycG1saWIoUGF5bG9hZElzWnN0ZCkA
|
||||||
|
My4wLjQtMQA0LjYuMC0xADQuMC0xADUuNC4xOC0xADYuMC4yAAAAAAAAAQAAAAEAAAAAAAAACDEt
|
||||||
|
MQAAAAAAZml4dHVyZS50eHQAL3Vzci9zaGFyZS9wYW5hbWEtcHJvdmVuYW5jZS1maXh0dXJlLwAt
|
||||||
|
TzIgLWZsdG89YXV0byAtZmZhdC1sdG8tb2JqZWN0cyAtZmV4Y2VwdGlvbnMgLWcgLWdyZWNvcmQt
|
||||||
|
Z2NjLXN3aXRjaGVzIC1waXBlIC1XYWxsIC1Xbm8tY29tcGxhaW4td3JvbmctbGFuZyAtV2Vycm9y
|
||||||
|
PWZvcm1hdC1zZWN1cml0eSAtV3AsLVVfRk9SVElGWV9TT1VSQ0UsLURfRk9SVElGWV9TT1VSQ0U9
|
||||||
|
MyAtV3AsLURfR0xJQkNYWF9BU1NFUlRJT05TIC1zcGVjcz0vdXNyL2xpYi9ycG0vcmVkaGF0L3Jl
|
||||||
|
ZGhhdC1oYXJkZW5lZC1jYzEgLWZzdGFjay1wcm90ZWN0b3Itc3Ryb25nIC1zcGVjcz0vdXNyL2xp
|
||||||
|
Yi9ycG0vcmVkaGF0L3JlZGhhdC1hbm5vYmluLWNjMSAgLW02NCAtbWFyY2g9eDg2LTY0IC1tdHVu
|
||||||
|
ZT1nZW5lcmljIC1mYXN5bmNocm9ub3VzLXVud2luZC10YWJsZXMgLWZzdGFjay1jbGFzaC1wcm90
|
||||||
|
ZWN0aW9uIC1mY2YtcHJvdGVjdGlvbiAtbXRscy1kaWFsZWN0PWdudTIgLWZuby1vbWl0LWZyYW1l
|
||||||
|
LXBvaW50ZXIgLW1uby1vbWl0LWxlYWYtZnJhbWUtcG9pbnRlcgBjcGlvAHpzdGQAMTkAbm9hcmNo
|
||||||
|
LXJlZGhhdC1saW51eC1nbnUAAAAAAAAAAAAAAEFTQ0lJIHRleHQAAAAAAAh1dGYtOABiZjZkYzg1
|
||||||
|
Y2I3NjI5MzhhYjM1NDY2ZDYyNWUzZWI0MzIxMzk4MjAxZWY5NDM5NDRhZDk0NzU5YjExMTY1Yjk5
|
||||||
|
AAAAAAAINDQ4YWY1YjI2NTgyODFlZGFhYTNmMGVlNDU5ZTk2MWVhZGYzNTEzZmI5MDBiOTQ0NDVi
|
||||||
|
YWZjNDUwZmQxYWY2NwAAAAA/AAAAB////NAAAAAQKLUv/QBofQMAkgUUGHBvDmCIWNNxsOnme3c1
|
||||||
|
JmpNprTcf+8pMqqqrTUmWRSEae6cAZ3ZfAvlNTMJcvCJHSFGycr11LGrhbIja6V17Xsg3Hgfw380
|
||||||
|
wR+ajfOLFw8MIACTzAMyvJyYeLFKvjdrmx/Z4OEGZKVOuIQR
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
mQENBGqQCOUBCADHP/S269aT5t0ZvePSetTa1h2KtcwiQ+LEkWMvHM8sYCrHDjer
|
||||||
|
XR53nj+e9xZPmXtEIiYsE1LpR7ax8dwcm/1XDqFLeduCRkB6DQE4Q5Ia1u9EXpjc
|
||||||
|
Of+uiw0Y2n1/d/BuRVOJiORlFMlW+0lueMaShHfH+/g2QC9oQdIMZfk+UaoRRgVf
|
||||||
|
5hpRfpIZGKOnAEatTRRbjDaoibIe0/El8Pwt93RoCO9GxF+UeJZZA152TOrB3Y/6
|
||||||
|
uTe7FE5HZFXQEvR78GhrAzmwZENuMIaIIaHhzOrLKrxoVtgimHymLe1rODQfq6zG
|
||||||
|
jRZ8SDJ2oLB1u51MiirV2fc18gUUPTbOSfv7ABEBAAG0KlBhbmFtYSBXcm9uZyBT
|
||||||
|
aWduZXIgPHdyb25nQHBhbmFtYS5pbnZhbGlkPokBUQQTAQoAOxYhBPDbF2/iFLrD
|
||||||
|
tbwnfM6LkqNI16KwBQJqkAjlAhsDBQsJCAcCAiICBhUKCQgLAgQWAgMBAh4HAheA
|
||||||
|
AAoJEM6LkqNI16KwbwgH/1yMS9PB7KQHLE+kQqaJQxqOLyANx4EPn8NeXB19XByz
|
||||||
|
Zph/qzFjnGXT/Lz2PMwqo4uem6oXYSdwXlsVM6oLeQ8wDd29/oLbI77cYBO42QSL
|
||||||
|
cerjc+IbJ7BCiqGL0e5Gmn8lzWinO+wramnVtDKQn4BzDCj7UWpBzyClqVb06IfL
|
||||||
|
9Xz4KMSv3vDGVMhtLLgVmfRkdgdgS1mcgQhSaueQmjU1Z4zQ8dHbL1cefuvxPKzM
|
||||||
|
XgkKBIIaY+2X1ulz/QA7fe4JpqNzyRC0gixod72OXldFA6aNV/EfF+1Pa/nVPNYC
|
||||||
|
MQl6tgcI8JX9lnsMxK+h9mAIilFQUmdX1Qio4FjWYLI=
|
||||||
|
=l5kF
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
@@ -47,6 +47,14 @@ snapshot() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
snapshot_gpg_state() {
|
||||||
|
local path="$1" file
|
||||||
|
[[ -d "$path" ]] || return 0
|
||||||
|
while IFS= read -r file; do
|
||||||
|
sha256sum "$file"
|
||||||
|
done < <(find "$path" -maxdepth 1 -type f \( -name pubring.kbx -o -name trustdb.gpg \) | sort)
|
||||||
|
}
|
||||||
|
|
||||||
# This must be the only production file sourced by the contract.
|
# This must be the only production file sourced by the contract.
|
||||||
# shellcheck source=../../setup/lib/artifact-provenance
|
# shellcheck source=../../setup/lib/artifact-provenance
|
||||||
source "$repo_dir/setup/lib/artifact-provenance"
|
source "$repo_dir/setup/lib/artifact-provenance"
|
||||||
@@ -55,30 +63,46 @@ fixture_fingerprint='6016FF18CAE298CE3648EE2325E01F765E1EF9FA'
|
|||||||
tiny_sha256='291bd319ae85488101e908e37fc0fa1b0da1429ba27e10d2b391cb3f60dd44ea'
|
tiny_sha256='291bd319ae85488101e908e37fc0fa1b0da1429ba27e10d2b391cb3f60dd44ea'
|
||||||
base64 --decode "$fixtures/signed-fixture.rpm.base64" > "$test_tmp/signed-fixture.rpm"
|
base64 --decode "$fixtures/signed-fixture.rpm.base64" > "$test_tmp/signed-fixture.rpm"
|
||||||
base64 --decode "$fixtures/unsigned-fixture.rpm.base64" > "$test_tmp/unsigned-fixture.rpm"
|
base64 --decode "$fixtures/unsigned-fixture.rpm.base64" > "$test_tmp/unsigned-fixture.rpm"
|
||||||
|
base64 --decode "$fixtures/wrong-signer-fixture.rpm.base64" > "$test_tmp/wrong-signer-fixture.rpm"
|
||||||
|
|
||||||
|
[[ "$(wc -l < "$fixtures/SHASUMS256.txt")" -eq 4 ]] || fail 'signed checksum fixture is not four lines'
|
||||||
|
[[ "$(cmp -l "$fixtures/tiny-artifact" "$fixtures/tiny-artifact-tampered" | wc -l)" -eq 1 ]] \
|
||||||
|
|| fail 'tampered artifact does not differ by exactly one byte'
|
||||||
|
|
||||||
expect_success key_fingerprint_matches "$fixtures/fixture-key.asc" "$fixture_fingerprint"
|
expect_success key_fingerprint_matches "$fixtures/fixture-key.asc" "$fixture_fingerprint"
|
||||||
expect_failure key_fingerprint_matches "$fixtures/fixture-key.asc" '0000000000000000000000000000000000000000'
|
expect_failure key_fingerprint_matches "$fixtures/fixture-key.asc" '0000000000000000000000000000000000000000'
|
||||||
|
cat "$fixtures/fixture-key.asc" "$fixtures/wrong-signer-key.asc" > "$test_tmp/combined-key.asc"
|
||||||
|
expect_failure key_fingerprint_matches "$test_tmp/combined-key.asc" "$fixture_fingerprint"
|
||||||
|
|
||||||
expect_success verify_detached_signature \
|
expect_success verify_detached_signature \
|
||||||
"$fixtures/fixture-key.asc" "$fixtures/SHASUMS256.txt.asc" "$fixtures/SHASUMS256.txt"
|
"$fixtures/fixture-key.asc" "$fixtures/SHASUMS256.txt.asc" "$fixtures/SHASUMS256.txt"
|
||||||
expect_failure verify_detached_signature \
|
expect_failure verify_detached_signature \
|
||||||
"$fixtures/fixture-key.asc" "$fixtures/SHASUMS256.txt.asc" "$fixtures/tiny-artifact"
|
"$fixtures/fixture-key.asc" "$fixtures/SHASUMS256.txt.asc" "$fixtures/tiny-artifact"
|
||||||
cp "$fixtures/SHASUMS256.txt.asc" "$test_tmp/bad-signature.asc"
|
cp "$fixtures/SHASUMS256.txt.asc" "$test_tmp/bad-signature.asc"
|
||||||
sed -i 's/^=nTYb$/=nTYa/' "$test_tmp/bad-signature.asc"
|
sed -i 's/^=MJqv$/=MJqa/' "$test_tmp/bad-signature.asc"
|
||||||
expect_failure verify_detached_signature \
|
expect_failure verify_detached_signature \
|
||||||
"$fixtures/fixture-key.asc" "$test_tmp/bad-signature.asc" "$fixtures/SHASUMS256.txt"
|
"$fixtures/fixture-key.asc" "$test_tmp/bad-signature.asc" "$fixtures/SHASUMS256.txt"
|
||||||
|
expect_failure verify_detached_signature \
|
||||||
|
"$test_tmp/combined-key.asc" "$fixtures/wrong-signer-SHASUMS256.txt.asc" "$fixtures/SHASUMS256.txt"
|
||||||
|
|
||||||
mkdir "$test_tmp/bin"
|
mkdir "$test_tmp/bin"
|
||||||
cat > "$test_tmp/bin/curl" <<'STUB'
|
cat > "$test_tmp/bin/curl" <<'STUB'
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
output=''
|
output=''
|
||||||
|
connect_timeout=''
|
||||||
|
max_time=''
|
||||||
|
max_filesize=''
|
||||||
while (($#)); do
|
while (($#)); do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--output) output="$2"; shift 2 ;;
|
--output) output="$2"; shift 2 ;;
|
||||||
|
--connect-timeout) connect_timeout="$2"; shift 2 ;;
|
||||||
|
--max-time) max_time="$2"; shift 2 ;;
|
||||||
|
--max-filesize) max_filesize="$2"; shift 2 ;;
|
||||||
*) shift ;;
|
*) shift ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
[[ "$connect_timeout" == 10 && "$max_time" == 600 && "$max_filesize" == "${CURL_EXPECTED_MAX_BYTES:?}" ]] || exit 65
|
||||||
case "${CURL_FIXTURE:?}" in
|
case "${CURL_FIXTURE:?}" in
|
||||||
good) cp "$CURL_FIXTURE_ROOT/tiny-artifact" "$output" ;;
|
good) cp "$CURL_FIXTURE_ROOT/tiny-artifact" "$output" ;;
|
||||||
oversized) head -c 1025 /dev/zero > "$output" ;;
|
oversized) head -c 1025 /dev/zero > "$output" ;;
|
||||||
@@ -88,7 +112,7 @@ esac
|
|||||||
STUB
|
STUB
|
||||||
chmod +x "$test_tmp/bin/curl"
|
chmod +x "$test_tmp/bin/curl"
|
||||||
PATH="$test_tmp/bin:$PATH"
|
PATH="$test_tmp/bin:$PATH"
|
||||||
export PATH CURL_FIXTURE_ROOT="$fixtures"
|
export PATH CURL_FIXTURE_ROOT="$fixtures" CURL_EXPECTED_MAX_BYTES=1024
|
||||||
|
|
||||||
destination="$test_tmp/destination"
|
destination="$test_tmp/destination"
|
||||||
export CURL_FIXTURE=good
|
export CURL_FIXTURE=good
|
||||||
@@ -108,6 +132,23 @@ expect_failure download_sha256 'https://fixture.invalid/bad-digest' \
|
|||||||
assert_file_bytes "$destination" 'known-good'
|
assert_file_bytes "$destination" 'known-good'
|
||||||
[[ ! -e "$destination.part" ]] || fail 'bad digest left a part file'
|
[[ ! -e "$destination.part" ]] || fail 'bad digest left a part file'
|
||||||
|
|
||||||
|
protected="$test_tmp/protected-known-good"
|
||||||
|
printf 'known-good\n' > "$protected"
|
||||||
|
ln -s "$protected" "$destination.part"
|
||||||
|
expect_failure download_sha256 'https://fixture.invalid/symlink-part' \
|
||||||
|
'0000000000000000000000000000000000000000000000000000000000000000' 1024 "$destination"
|
||||||
|
assert_file_bytes "$protected" 'known-good'
|
||||||
|
[[ -L "$destination.part" ]] || fail 'symlinked destination part was not preserved'
|
||||||
|
rm -f -- "$destination.part"
|
||||||
|
|
||||||
|
ln "$protected" "$destination.part"
|
||||||
|
expect_failure download_sha256 'https://fixture.invalid/hard-link-part' \
|
||||||
|
'0000000000000000000000000000000000000000000000000000000000000000' 1024 "$destination"
|
||||||
|
assert_file_bytes "$protected" 'known-good'
|
||||||
|
[[ "$(stat -c %i "$protected")" == "$(stat -c %i "$destination.part")" ]] \
|
||||||
|
|| fail 'hard-linked destination part was not preserved'
|
||||||
|
rm -f -- "$destination.part"
|
||||||
|
|
||||||
export CURL_FIXTURE=oversized
|
export CURL_FIXTURE=oversized
|
||||||
expect_failure download_sha256 'https://fixture.invalid/oversized' "$tiny_sha256" 1024 "$destination"
|
expect_failure download_sha256 'https://fixture.invalid/oversized' "$tiny_sha256" 1024 "$destination"
|
||||||
assert_file_bytes "$destination" 'known-good'
|
assert_file_bytes "$destination" 'known-good'
|
||||||
@@ -119,6 +160,7 @@ assert_file_bytes "$destination" 'known-good'
|
|||||||
[[ ! -e "$destination.part" ]] || fail 'interrupted download left a part file'
|
[[ ! -e "$destination.part" ]] || fail 'interrupted download left a part file'
|
||||||
|
|
||||||
before_gnupg="$(snapshot "$host_gnupg")"
|
before_gnupg="$(snapshot "$host_gnupg")"
|
||||||
|
before_gpg_files="$(snapshot_gpg_state "$host_gnupg")"
|
||||||
before_rpmdb="$(snapshot "$host_rpmdb")"
|
before_rpmdb="$(snapshot "$host_rpmdb")"
|
||||||
expect_success rpm_signature_matches \
|
expect_success rpm_signature_matches \
|
||||||
"$test_tmp/signed-fixture.rpm" "$fixtures/fixture-key.asc" "$fixture_fingerprint"
|
"$test_tmp/signed-fixture.rpm" "$fixtures/fixture-key.asc" "$fixture_fingerprint"
|
||||||
@@ -126,11 +168,29 @@ expect_failure rpm_signature_matches \
|
|||||||
"$test_tmp/unsigned-fixture.rpm" "$fixtures/fixture-key.asc" "$fixture_fingerprint"
|
"$test_tmp/unsigned-fixture.rpm" "$fixtures/fixture-key.asc" "$fixture_fingerprint"
|
||||||
expect_failure rpm_signature_matches \
|
expect_failure rpm_signature_matches \
|
||||||
"$test_tmp/signed-fixture.rpm" "$fixtures/fixture-key.asc" '0000000000000000000000000000000000000000'
|
"$test_tmp/signed-fixture.rpm" "$fixtures/fixture-key.asc" '0000000000000000000000000000000000000000'
|
||||||
|
expect_failure rpm_signature_matches \
|
||||||
|
"$test_tmp/wrong-signer-fixture.rpm" "$fixtures/fixture-key.asc" "$fixture_fingerprint"
|
||||||
|
expect_failure rpm_signature_matches \
|
||||||
|
"$test_tmp/wrong-signer-fixture.rpm" "$test_tmp/combined-key.asc" "$fixture_fingerprint"
|
||||||
[[ "$before_gnupg" == "$(snapshot "$host_gnupg")" ]] || fail 'host GPG state changed'
|
[[ "$before_gnupg" == "$(snapshot "$host_gnupg")" ]] || fail 'host GPG state changed'
|
||||||
|
[[ "$before_gpg_files" == "$(snapshot_gpg_state "$host_gnupg")" ]] || fail 'host GPG keybox or trust database changed'
|
||||||
[[ "$before_rpmdb" == "$(snapshot "$host_rpmdb")" ]] || fail 'host RPM database changed'
|
[[ "$before_rpmdb" == "$(snapshot "$host_rpmdb")" ]] || fail 'host RPM database changed'
|
||||||
|
|
||||||
expect_success load_installer_provenance "$config"
|
expect_success load_installer_provenance "$config"
|
||||||
[[ "${INSTALLER_PROVENANCE[BUN_VERSION]:-}" == '1.4.0' ]] || fail 'valid provenance was not loaded'
|
[[ "${INSTALLER_PROVENANCE[BUN_VERSION]:-}" == '1.4.0' ]] || fail 'valid provenance was not loaded'
|
||||||
|
for key_spec in \
|
||||||
|
'terra44 TERRA_FINGERPRINT' \
|
||||||
|
'claude-code CLAUDE_CODE_FINGERPRINT' \
|
||||||
|
'bun BUN_FINGERPRINT' \
|
||||||
|
'rpmfusion-free RPMFUSION_FREE_FINGERPRINT' \
|
||||||
|
'rpmfusion-nonfree RPMFUSION_NONFREE_FINGERPRINT' \
|
||||||
|
'hyprland-copr HYPRLAND_COPR_FINGERPRINT' \
|
||||||
|
'flathub FLATHUB_FINGERPRINT' \
|
||||||
|
'claude-desktop CLAUDE_DESKTOP_FINGERPRINT'; do
|
||||||
|
read -r key_file fingerprint_name <<<"$key_spec"
|
||||||
|
expect_success key_fingerprint_matches "$repo_dir/setup/provenance/keys/$key_file.asc" \
|
||||||
|
"${INSTALLER_PROVENANCE[$fingerprint_name]}"
|
||||||
|
done
|
||||||
|
|
||||||
parser_fixture="$test_tmp/installers.conf"
|
parser_fixture="$test_tmp/installers.conf"
|
||||||
cp "$config" "$parser_fixture"
|
cp "$config" "$parser_fixture"
|
||||||
|
|||||||
Reference in New Issue
Block a user