Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ Use helpers from `update/update_lib.py`: `latest_github_release`, `latest_docker

If an image has no resolvable tag pattern, the script may raise `NotImplementedError`; the orchestrator reports it as `error` and the run continues.

For apps whose updates must be done manually — self-built images (e.g. `mosquitto`), or upstreams whose Docker tags are unreliable for auto-detection (e.g. `joplin-server`, where Docker Hub publishes prerelease tags without flagging them) — raise `update.update_lib.OptOut("<reason>")` instead. The orchestrator reports them as `opt_out` (distinct from `error`) with the reason string preserved, so the choice stays discoverable in every check run.
For apps whose updates must be done manually — self-built images, or upstreams whose Docker tags are unreliable for auto-detection (e.g. `joplin-server`, where Docker Hub publishes prerelease tags without flagging them) — raise `update.update_lib.OptOut("<reason>")` instead. The orchestrator reports them as `opt_out` (distinct from `error`) with the reason string preserved, so the choice stays discoverable in every check run.

## Checklist for Adding a New App

Expand Down
8 changes: 5 additions & 3 deletions apps/mosquitto/app_meta.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
{
"v": "1.0",
"app_version": "0.1.0",
"v": "1.2",
"app_version": "2.0.22",
"name": "mosquitto",
"pretty_name": "Mosquitto",
"icon": "icon.png",
"homepage": "https://mosquitto.org/",
"upstream_repo": "https://github.com/eclipse-mosquitto/mosquitto",
"entrypoints": [
{
"container_name": "mosquitto",
Expand Down Expand Up @@ -37,5 +40,4 @@
],
"is_featured": true
}

}
109 changes: 108 additions & 1 deletion apps/mosquitto/docker-compose.yml.template
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,116 @@ networks:
services:
mosquitto:
restart: always
image: portalapps.azurecr.io/ptl-apps/mosquitto:main
image: eclipse-mosquitto:2.0.22
container_name: mosquitto
volumes:
- "{{ fs.app_data }}/mosquitto/config:/mosquitto/config"
networks:
- portal
command:
- /bin/sh
- -c
- |
set -e
if [ -z "$$(ls -A /mosquitto/config)" ]; then
cat > /mosquitto/config/mosquitto.conf <<'CONF'
listener 1883
protocol mqtt

listener 9001
protocol websockets

require_certificate false

per_listener_settings false

plugin /usr/lib/mosquitto_dynamic_security.so
plugin_opt_config_file /mosquitto/config/dynamic_security.json
CONF
cat > /mosquitto/config/dynamic_security.json <<'DYNSEC'
{
"defaultACLAccess": {
"publishClientSend": false,
"publishClientReceive": true,
"subscribe": false,
"unsubscribe": true
},
"clients": [
{
"username": "admin",
"textname": "Dynsec admin user",
"roles": [
{
"rolename": "admin"
}
],
"password": "xHrePRFxvhHRGCWpXzg3TWAnPUc9MoDFTah68IWPgOPVf2bzX1Sl8OjqMnGp8SAg6KtaHWIG5l8HocL0Qii4pw==",
"salt": "4ad7/uINpqWDaFQA",
"iterations": 101
}
],
"groups": [],
"roles": [
{
"rolename": "admin",
"acls": [
{
"acltype": "publishClientSend",
"topic": "$$CONTROL/dynamic-security/#",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientReceive",
"topic": "$$CONTROL/dynamic-security/#",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientReceive",
"topic": "$$SYS/#",
"priority": 0,
"allow": true
},
{
"acltype": "publishClientReceive",
"topic": "#",
"priority": 0,
"allow": true
},
{
"acltype": "subscribePattern",
"topic": "$$CONTROL/dynamic-security/#",
"priority": 0,
"allow": true
},
{
"acltype": "subscribePattern",
"topic": "$$SYS/#",
"priority": 0,
"allow": true
},
{
"acltype": "subscribePattern",
"topic": "#",
"priority": 0,
"allow": true
},
{
"acltype": "unsubscribePattern",
"topic": "#",
"priority": 0,
"allow": true
}
]
}
]
}
DYNSEC
chown mosquitto:mosquitto /mosquitto/config/dynamic_security.json
chmod 0700 /mosquitto/config/dynamic_security.json
echo "seeded initial mosquitto config"
else
echo "existing mosquitto config found, leaving it untouched"
fi
exec /usr/sbin/mosquitto -c /mosquitto/config/mosquitto.conf
31 changes: 27 additions & 4 deletions apps/mosquitto/update_check.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,30 @@
from update.update_lib import OptOut
import re

from update.update_lib import _http_get_text, latest_dockerhub_tag

# Upstream publishes git tags and Docker images but no GitHub releases, so
# Docker Hub is the authoritative tag source and ChangeLog.txt the release notes.
# Plain `X.Y.Z` tags are the 2.0 line; the 2.1 line is published as
# `2.1.x-alpine` only and is deliberately not matched here.
TAG_RE = r"^\d+\.\d+\.\d+$"
CHANGELOG_RAW = "https://raw.githubusercontent.com/eclipse-mosquitto/mosquitto/v{version}/ChangeLog.txt"
CHANGELOG_HTML = "https://github.com/eclipse-mosquitto/mosquitto/blob/v{version}/ChangeLog.txt"


def _changelog_section(version: str) -> str:
text = _http_get_text(CHANGELOG_RAW.format(version=version))
match = re.search(
rf"^{re.escape(version)} - .*?(?=^\d+\.\d+\.\d+ - )",
text,
re.MULTILINE | re.DOTALL,
)
return match.group(0).strip() if match else ""


def check(current_version: str) -> dict:
# Image is a private build at portalapps.azurecr.io; not auto-updatable.
# Bumps must be done manually after rebuilding the image.
raise OptOut("self-built image, manual updates only")
latest = latest_dockerhub_tag("eclipse-mosquitto", filter_regex=TAG_RE)
return {
"latest_version": latest,
"release_notes_url": CHANGELOG_HTML.format(version=latest),
"release_body": _changelog_section(latest),
}
Loading