1
0
Fork 0
mirror of https://github.com/YunoHost/apps.git synced 2024-09-03 20:06:07 +02:00

Implement an app rejection list (#2515)

Co-authored-by: Alexandre Aubin <alex.aubin@mailoo.org>
Co-authored-by: OniriCorpe <oniricorpe@yunohost.org>
This commit is contained in:
tituspijean 2024-08-18 01:52:37 +02:00 committed by GitHub
parent 6b6ded9f0f
commit 71800d21b6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 332 additions and 43 deletions

212
rejectedlist.toml Normal file
View file

@ -0,0 +1,212 @@
[sillytavern]
name = "SillyTavern"
description = "LLM Frontend for power users"
upstream = "https://github.com/SillyTavern/SillyTavern"
website = "https://sillytavern.app/"
reason = "Based on a LLM"
[e621-image-hosting]
name = "e621 image hosting"
description = "An Imageboard with a heavy focus on tagging and searchability"
upstream = "https://github.com/e621ng/e621ng"
website = ""
reason = "Docker-compose mess"
[photo-sphere-viewer]
name = "Photo Sphere Viewer"
description = "A JavaScript library to display 360° sphere panoramas. Very customizable."
upstream = "https://github.com/mistic100/Photo-Sphere-Viewer"
website = "https://photo-sphere-viewer.js.org/"
reason = "Just a library, can be integrated in a My Webapp"
[minecraft-bedrock-server]
name = "Minecraft Bedrock Server"
description = "This allows you to host your own world server on Minecraft Bedrock Edition."
upstream = "https://github.com/TheRemote/MinecraftBedrockServer"
website = "https://jamesachambers.com/minecraft-bedrock-edition-ubuntu-dedicated-server-guide/"
reason = "MineCraft is not free, whatever its flavour"
[kirbycms]
name = "KirbyCMS"
description = "Kirby: the CMS that adapts to any project, loved by developers and editors alike."
upstream = "https://github.com/getkirby/kirby"
website = "https://getkirby.com/"
reason = "Not free"
[coolify]
name = "Coolify"
description = "Alternative à Vercel"
upstream = "https://github.com/coollabsio/coolify"
website = "https://coolify.io/"
reason = "Does not make sense to integrate in YunoHost, and most likely incompatible anyways"
[chatmail]
name = "chatmail"
description = "Deltachat server"
upstream = "https://github.com/deltachat/chatmail"
website = "https://delta.chat/en/2023-12-13-chatmail"
reason = "YunoHost already integrates a mail server"
[stalwart-mail-server]
name = "Stalwart Mail Server"
description = "Modern All-in-One Mail Server (IMAP, JMAP, SMTP) written in Rust."
upstream = "https://github.com/stalwartlabs/mail-server"
website = "https://stalw.art"
reason = "YunoHost already integrates a mail server"
[retronas]
name = "RetroNAS"
description = "It allows you to store ROMs and sync to different consoles with networking connecting."
upstream = "https://github.com/retronas/retronas"
website = ""
reason = "Big scary security warning in the app's README"
[quakejs]
name = "QuakeJS"
description = "QuakeJS allows you to play Quake III Arena Multiplayer on Web Browser using JavaScript."
upstream = "https://github.com/inolen/quakejs"
website = "http://www.quakejs.com/"
reason = "Unmaintained project"
[speckle-server]
name = "Speckle Server"
description = "Data infrastructure for the AEC industry."
upstream = "https://github.com/specklesystems/speckle-server"
website = "https://speckle.systems/"
reason = "Too niche of a use case, and no Docker-less install options"
[graphite]
name = "Graphite"
description = "Création non destructive d'image"
upstream = "https://github.com/GraphiteEditor/Graphite"
website = "https://graphite.rs/"
reason = "No self-hosting documentation"
[affine]
name = "Affine"
description = "Wiki, écriture de document, Mindmap, Moodboard, un melting polt d'outil pour créer divers document."
upstream = "https://github.com/toeverything/AFFiNE"
website = "https://affine.pro/"
reason = "Unclear license and too big of a framework"
[authentik]
name = "authentik"
description = "Replace Active Directory, Okta and Auth0. Supports OIDC, SAML, LDAP, SCIM, Radius, and Proxy."
upstream = "https://github.com/goauthentik/authentik"
website = "https://goauthentik.io/"
reason = "YunoHost already integrates a SSO, it will conflict."
[mirlo]
name = "Mirlo"
description = "Mirlo provides a user-friendly space to help musicians sell music, manage subscriptions, and share w"
upstream = "https://github.com/funmusicplace/mirlo/"
website = ""
reason = "Too big of a Docker-compose mess"
[h5p]
name = "H5P"
description = "This collection of tools aim to creates interactive exercices for learning purposes."
upstream = "https://github.com/h5p"
website = "https://h5p.org/"
reason = "The tools are spread across too many repos, making packaging difficult"
[gophish]
name = "Gophish"
description = "Phishing toolkit for security awareness training and penetration testers"
upstream = "https://github.com/gophish/gophish"
website = "https://getgophish.com"
reason = "Too niche of a use case"
[pdftochat]
name = "PDFTOCHAT"
description = "Chat with your PDFs in seconds. Powered by Together AI and Pinecone."
upstream = "https://github.com/Nutlope/pdftochat"
website = "https://www.pdftochat.com/"
reason = "whatthefuck.gif, also AI"
[jam]
name = "Jam"
description = "With Jam you can create audio rooms that can be used for panel discussions, jam sessions, ..."
upstream = "https://github.com/jam-systems/jam"
website = "https://jam.systems/"
reason = "Unmaintained"
[bluesky-pds]
name = "Bluesky PDS"
description = "Personal Data Server for Bluesky, federated social network based on the AT protocol."
upstream = "https://github.com/bluesky-social/pds"
website = "https://bsky.social/about"
reason = "One of the principles at the heart of the YunoHost project is to be a modest counterweight to GAFAM and surveillance capitalism, [...] [not to] provide a ready-to-use tool to our users to be part of it directly"
[anysync]
name = "AnySync"
description = "Allows sync between devices for Aytype."
upstream = "https://github.com/anyproto/any-sync"
website = "https://anytype.io/"
reason = "Clients are not totally free"
[dub]
name = "dub"
description = "Open-source link management infrastructure."
upstream = "https://github.com/dubinc/dub"
website = "https://dub.co"
reason = "Tracking system, against YunoHost core values"
[maybe]
name = "Maybe"
description = "The OS for your personal finances"
upstream = "https://github.com/maybe-finance/maybe"
website = "https://hello.maybe.co"
reason = "Surely not ready for self-hosting"
[osclass]
name = "Osclass"
description = "Classifieds website"
upstream = "https://github.com/osclass/Osclass"
website = "https://osclass-classifieds.com"
reason = "Unmaintained"
[opentalk]
name = "OpenTalk"
description = "German developed, modern, conferencing tool running in browser alone."
upstream = "https://gitlab.opencode.de/opentalk"
website = "https://opentalk.eu/en"
reason = "Looks unpackageable"
[verdaccio]
name = "Verdaccio"
description = "Locally managed backup & proxy for npm package registry."
upstream = "https://github.com/verdaccio/verdaccio"
website = "https://verdaccio.org/"
reason = "Too niche of a use case"
[tabula]
name = "Tabula"
description = "Extract tables from PDF; single executable .jar on 127.0.0.1.\r\rComparable to Excalibur, I think."
upstream = "https://github.com/tabulapdf/tabula"
website = "https://tabula.technology/"
reason = "Unmaintained"
[llamafile]
name = "Llamafile"
description = "Single file LLMs from Mozilla Innovation Projects, that will run locally on any available processors"
upstream = "https://github.com/Mozilla-Ocho/llamafile"
website = "https://hacks.mozilla.org/2023/11/introducing-llamafile/"
reason = "Not packageable as is, it is a binary tool for other apps"
[fastchat]
name = "FastChat"
description = "- open platform for LLM chatbots incl training, evaluating, & serving via openai-compatible APIs."
upstream = "https://github.com/lm-sys/FastChat"
website = "https://chat.lmsys.org/"
reason = "YunoHost packagers do not wish to promote AI, and training AIs is not lean"
[slidge]
name = "Slidge"
description = "XMPP (puppeteer) gateway library to other instant messenger platforms/protocols."
upstream = "https://sr.ht/~nicoco/slidge/sources"
website = "https://sr.ht/~nicoco/slidge/"
reason = "This is only a library, so not packageable as is"

View file

@ -364,6 +364,24 @@ def add_to_wishlist():
), ),
) )
rejectedlist_rawtoml = repo.get_contents(
"rejectedlist.toml", ref=repo.default_branch
)
rejectedlist_rawtoml = rejectedlist_rawtoml.decoded_content.decode()
rejectedlist = tomlkit.loads(rejectedlist_rawtoml)
for rejectedslug, rejectedinfo in rejectedlist.items():
if upstream.strip("/ ") in rejectedinfo["upstream"]:
return render_template(
"wishlist_add.html",
csrf_token=csrf_token,
successmsg=None,
errormsg=_(
"We're sorry, but this app is listed among the already declined apps. The specified reason is:<br /><q>%(reason)s</q>",
reason=rejectedinfo["reason"],
),
)
app_catalog = get_catalog()["apps"] app_catalog = get_catalog()["apps"]
if slug in app_catalog: if slug in app_catalog:

View file

@ -10,6 +10,7 @@ import tempfile
import aiohttp import aiohttp
import logging import logging
from pathlib import Path from pathlib import Path
import re
from typing import Optional from typing import Optional
from git import Actor, Repo, GitCommandError from git import Actor, Repo, GitCommandError
@ -116,6 +117,8 @@ def on_push(request: Request) -> HTTPResponse:
repository = data["repository"]["full_name"] repository = data["repository"]["full_name"]
branch = data["ref"].split("/", 2)[2] branch = data["ref"].split("/", 2)[2]
if repository.startswith("YunoHost-Apps/"):
logging.info(f"{repository} -> branch '{branch}'") logging.info(f"{repository} -> branch '{branch}'")
need_push = False need_push = False
@ -149,11 +152,23 @@ def on_pr_comment(request: Request, pr_infos: dict) -> HTTPResponse:
body = request.json["comment"]["body"].strip()[:100].lower() body = request.json["comment"]["body"].strip()[:100].lower()
# Check the comment contains proper keyword trigger # Check the comment contains proper keyword trigger
BUMP_REV_COMMANDS = ["!bump", "!new_revision", "!newrevision"] BUMP_REV_COMMANDS = ["!bump", "!new_revision", "!newrevision"]
if any(trigger.lower() in body for trigger in BUMP_REV_COMMANDS): if any(trigger.lower() in body for trigger in BUMP_REV_COMMANDS):
bump_revision(request, pr_infos) bump_revision(request, pr_infos)
return response.text("ok") return response.text("ok")
REJECT_WISHLIST_COMMANDS = ["!reject", "!nope"]
if any(trigger.lower() in body for trigger in REJECT_WISHLIST_COMMANDS):
reason = ""
for command in REJECT_WISHLIST_COMMANDS:
try:
reason = re.search(f"{command} (.*)", body).group(1).rstrip()
except:
pass
reject_wishlist(request, pr_infos, reason)
return response.text("ok")
return response.empty() return response.empty()
@ -162,6 +177,8 @@ def bump_revision(request: Request, pr_infos: dict) -> HTTPResponse:
repository = data["repository"]["full_name"] repository = data["repository"]["full_name"]
branch = pr_infos["head"]["ref"] branch = pr_infos["head"]["ref"]
if repository.startswith("YunoHost-Apps/"):
logging.info(f"Will bump revision on {repository} branch {branch}...") logging.info(f"Will bump revision on {repository} branch {branch}...")
with tempfile.TemporaryDirectory() as folder_str: with tempfile.TemporaryDirectory() as folder_str:
folder = Path(folder_str) folder = Path(folder_str)
@ -188,6 +205,48 @@ def bump_revision(request: Request, pr_infos: dict) -> HTTPResponse:
repo.remote().push(quiet=False, all=True) repo.remote().push(quiet=False, all=True)
return response.text("ok") return response.text("ok")
def reject_wishlist(request: Request, pr_infos: dict, reason=None) -> HTTPResponse:
data = request.json
repository = data["repository"]["full_name"]
branch = pr_infos["head"]["ref"]
if repository == "YunoHost/apps" and branch.startswith("add-to-wishlist"):
logging.info(f"Will put the suggested app in the rejected list on {repository} branch {branch}...")
with tempfile.TemporaryDirectory() as folder_str:
folder = Path(folder_str)
repo = Repo.clone_from(
f"https://{github_login()}:{github_token()}@github.com/{repository}",
to_path=folder,
)
repo.git.checkout(branch)
rejectedlist_file = (folder / "rejectedlist.toml")
rejectedlist = tomlkit.load(rejectedlist_file.open("r", encoding="utf-8"))
wishlist_file = (folder / "wishlist.toml")
wishlist = tomlkit.load(wishlist_file.open("r", encoding="utf-8"))
suggestedapp_slug = branch.replace("add-to-wishlist-", "")
suggestedapp = {suggestedapp_slug:wishlist[suggestedapp_slug]}
suggestedapp[suggestedapp_slug]["rejection_pr"] = pr_infos["html_url"]
suggestedapp[suggestedapp_slug]["reason"] = reason
wishlist.pop(suggestedapp_slug)
rejectedlist.update(suggestedapp)
tomlkit.dump(rejectedlist, rejectedlist_file.open("w", encoding="utf-8"))
tomlkit.dump(wishlist, wishlist_file.open("w", encoding="utf-8"))
repo.git.add("rejectedlist.toml")
repo.git.add("wishlist.toml")
suggestedapp_name = suggestedapp[suggestedapp_slug]["name"]
repo.index.commit(f"Reject {suggestedapp_name} from catalog", author=Actor("yunohost-bot", "yunohost@yunohost.org"))
logging.debug(f"Pushing {repository}")
repo.remote().push(quiet=False, all=True, force=True)
return response.text("ok")
def generate_and_commit_readmes(repo: Repo) -> bool: def generate_and_commit_readmes(repo: Repo) -> bool:
assert repo.working_tree_dir is not None assert repo.working_tree_dir is not None