diff --git a/aurweb/git/update.py b/aurweb/git/update.py index 467b540f..cd7813e0 100755 --- a/aurweb/git/update.py +++ b/aurweb/git/update.py @@ -315,6 +315,14 @@ def validate_metadata(metadata, commit): # noqa: C901 die_commit("missing source file: {:s}".format(fname), str(commit.id)) +def validate_blob_size(blob: pygit2.Object, commit: pygit2.Commit): + if isinstance(blob, pygit2.Blob) and blob.size > max_blob_size: + die_commit( + "maximum blob size ({:s}) exceeded".format(size_humanize(max_blob_size)), + str(commit.id), + ) + + def main(): # noqa: C901 repo = pygit2.Repository(repo_path) @@ -376,25 +384,42 @@ def main(): # noqa: C901 for commit in walker: if "PKGBUILD" not in commit.tree: die_commit("missing PKGBUILD", str(commit.id)) + + # Iterate over files in root dir for treeobj in commit.tree: - blob = repo[treeobj.id] - - if isinstance(blob, pygit2.Tree): + # Don't allow any subdirs besides "keys/" + if isinstance(treeobj, pygit2.Tree) and treeobj.name != "keys": die_commit( - "the repository must not contain subdirectories", str(commit.id) - ) - - if not isinstance(blob, pygit2.Blob): - die_commit("not a blob object: {:s}".format(treeobj), str(commit.id)) - - if blob.size > max_blob_size: - die_commit( - "maximum blob size ({:s}) exceeded".format( - size_humanize(max_blob_size) - ), + "the repository must not contain subdirectories", str(commit.id), ) + # Check size of files in root dir + validate_blob_size(treeobj, commit) + + # If we got a subdir keys/, + # make sure it only contains a pgp/ subdir with key files + if "keys" in commit.tree: + # Check for forbidden files/dirs in keys/ + for keyobj in commit.tree["keys"]: + if not isinstance(keyobj, pygit2.Tree) or keyobj.name != "pgp": + die_commit( + "the keys/ subdir may only contain a pgp/ directory", + str(commit.id), + ) + # Check for forbidden files in keys/pgp/ + if "keys/pgp" in commit.tree: + for pgpobj in commit.tree["keys/pgp"]: + if not isinstance(pgpobj, pygit2.Blob) or not pgpobj.name.endswith( + ".asc" + ): + die_commit( + "the subdir may only contain .asc (PGP pub key) files", + str(commit.id), + ) + # Check file size for pgp key files + validate_blob_size(pgpobj, commit) + # Display a warning if .SRCINFO is unchanged. if sha1_old not in ("0000000000000000000000000000000000000000", sha1_new): srcinfo_id_old = repo[sha1_old].tree[".SRCINFO"].id diff --git a/test/t1300-git-update.t b/test/t1300-git-update.t index a8ea5cab..4fdb487b 100755 --- a/test/t1300-git-update.t +++ b/test/t1300-git-update.t @@ -191,7 +191,7 @@ test_expect_success 'Removing PKGBUILD.' ' grep -q "^error: missing PKGBUILD$" actual ' -test_expect_success 'Pushing a tree with a subdirectory.' ' +test_expect_success 'Pushing a tree with a forbidden subdirectory.' ' old=$(git -C aur.git rev-parse HEAD) && test_when_finished "git -C aur.git reset --hard $old" && mkdir aur.git/subdir && @@ -205,6 +205,107 @@ test_expect_success 'Pushing a tree with a subdirectory.' ' grep -q "^error: the repository must not contain subdirectories$" actual ' +test_expect_success 'Pushing a tree with an allowed subdirectory for pgp keys; wrong files.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/pgp/ && + touch aur.git/keys/pgp/nonsense && + git -C aur.git add keys/pgp/nonsense && + git -C aur.git commit -q -m "Add some nonsense" && + new=$(git -C aur.git rev-parse HEAD) && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: the subdir may only contain .asc (PGP pub key) files$" actual +' + +test_expect_success 'Pushing a tree with an allowed subdirectory for pgp keys; another subdir.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/pgp/bla/ && + touch aur.git/keys/pgp/bla/x.asc && + git -C aur.git add keys/pgp/bla/x.asc && + git -C aur.git commit -q -m "Add some nonsense" && + new=$(git -C aur.git rev-parse HEAD) && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: the subdir may only contain .asc (PGP pub key) files$" actual +' + +test_expect_success 'Pushing a tree with an allowed subdirectory for pgp keys; wrong subdir.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/xyz/ && + touch aur.git/keys/xyz/x.asc && + git -C aur.git add keys/xyz/x.asc && + git -C aur.git commit -q -m "Add some nonsense" && + new=$(git -C aur.git rev-parse HEAD) && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: the keys/ subdir may only contain a pgp/ directory$" actual +' + +test_expect_success 'Pushing a tree with an allowed subdirectory with pgp keys; additional files' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/pgp/ && + touch aur.git/keys/pgp/x.asc && + touch aur.git/keys/nonsense && + git -C aur.git add keys/pgp/x.asc && + git -C aur.git add keys/nonsense && + git -C aur.git commit -q -m "Add pgp key" && + new=$(git -C aur.git rev-parse HEAD) && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: the keys/ subdir may only contain a pgp/ directory$" actual +' + +test_expect_success 'Pushing a tree with an allowed subdirectory with pgp keys; additional subdir' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/pgp/ && + mkdir -p aur.git/somedir/ && + touch aur.git/keys/pgp/x.asc && + touch aur.git/somedir/nonsense && + git -C aur.git add keys/pgp/x.asc && + git -C aur.git add somedir/nonsense && + git -C aur.git commit -q -m "Add pgp key" && + new=$(git -C aur.git rev-parse HEAD) && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: the repository must not contain subdirectories$" actual +' + +test_expect_success 'Pushing a tree with an allowed subdirectory with pgp keys; keys to large' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/pgp/ && + printf "%256001s" x > aur.git/keys/pgp/x.asc && + git -C aur.git add keys/pgp/x.asc && + git -C aur.git commit -q -m "Add pgp key" && + new=$(git -C aur.git rev-parse HEAD) && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: maximum blob size (250.00KiB) exceeded$" actual +' + +test_expect_success 'Pushing a tree with an allowed subdirectory with pgp keys.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/pgp/ && + touch aur.git/keys/pgp/x.asc && + git -C aur.git add keys/pgp/x.asc && + git -C aur.git commit -q -m "Add pgp key" && + new=$(git -C aur.git rev-parse HEAD) && + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + test_expect_success 'Pushing a tree with a large blob.' ' old=$(git -C aur.git rev-parse HEAD) && test_when_finished "git -C aur.git reset --hard $old" &&