fix: complete open-source delivery and isolate community CI
This commit is contained in:
+1
-6
@@ -17,15 +17,10 @@ IMAGE_URL_ALLOWED_HOSTS=
|
||||
BUILD_COMMIT=development
|
||||
BUILD_TIME=unknown
|
||||
|
||||
# Optional read-only NAS photo mount; use deploy/docker-compose.photos.yml.
|
||||
# NAS_PHOTOS_DIR=/volume2/photo
|
||||
# PHOTO_ROOT=/photos
|
||||
# Filesystem/NFS photo sources are retired. Use Synology Photos API or WebDAV.
|
||||
# Optional WebDAV credential reference; prefer a secret file under /config.
|
||||
# FRAME_FLOW_SOURCE_CLOUD_FILE=/config/webdav-cloud.secret
|
||||
|
||||
# Optional existing group with photo read permission; does not change NAS ACLs.
|
||||
# NAS_PHOTOS_GID=101
|
||||
|
||||
# Optional Synology Photos shared-space people filter. Configure a pinned NAS endpoint.
|
||||
# Login in the photo-source editor; only the session is saved in /config (mode 0600).
|
||||
SYNOLOGY_PHOTOS_URL=
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
name: Community checks
|
||||
on:
|
||||
push:
|
||||
branches: ["**"]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
verify:
|
||||
# GitHub-hosted disposable runner only; never run forks on the NAS runner.
|
||||
if: github.server_url == 'https://github.com'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
||||
with:
|
||||
python-version: '3.14'
|
||||
- run: python -m pip install -e '.[test]'
|
||||
- run: python -m ruff check pigway_frame_flow tests scripts
|
||||
- run: python -m ruff format --check pigway_frame_flow tests scripts
|
||||
- run: python -m mypy pigway_frame_flow
|
||||
- run: python -m pytest -q
|
||||
- run: python scripts/ci-audit.py
|
||||
@@ -8,7 +8,7 @@ on:
|
||||
jobs:
|
||||
verify:
|
||||
# The NAS Docker runner must never execute code from external forks.
|
||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
||||
if: github.server_url != 'https://github.com' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKER_PIP_INDEX_URL: ${{ vars.DOCKER_PIP_INDEX_URL }}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Contributing
|
||||
|
||||
Use Python 3.14.x and follow the development commands in README.md. Run Ruff
|
||||
lint/format checks, mypy and pytest before submitting a pull request. Keep changes
|
||||
focused and include a regression test for behavior fixes where practical.
|
||||
|
||||
Use mock mode with device writes disabled. Do not commit `.env`, credentials,
|
||||
private configuration, databases, photos, or production receipts. Tests must not
|
||||
contact real frames or mutate production services.
|
||||
|
||||
GitHub mirrors run community checks on disposable GitHub-hosted runners, including
|
||||
fork PRs. Gitea uses the existing trusted NAS runner and rejects fork PRs; maintainers
|
||||
review contributions before moving them to a trusted branch. Docker build/smoke
|
||||
verification remains in Gitea CI. Production releases are maintainer-controlled;
|
||||
contributors do not need access to production infrastructure.
|
||||
|
||||
For security issues, follow SECURITY.md instead of posting exploit details publicly.
|
||||
Contributions are provided under the project's MIT license; preserve third-party
|
||||
licenses and provenance when introducing external code or assets.
|
||||
@@ -37,6 +37,7 @@ RUN --mount=type=cache,id=frameflow-pip-py314-${TARGETARCH},target=/root/.cache/
|
||||
else python /build-tools/install.py --locked; fi
|
||||
COPY pigway_frame_flow ./pigway_frame_flow
|
||||
COPY vendor ./vendor
|
||||
COPY LICENSE NOTICE.md ./
|
||||
# Publish only the cleaned filesystem, without retaining build-stage layers.
|
||||
RUN rm -rf /usr/local/lib/python*/site-packages/pip \
|
||||
/usr/local/lib/python*/site-packages/pip-*.dist-info \
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# PIGWay Frame Flow
|
||||
|
||||
Development currently supports Python 3.14.x. See [contributing](CONTRIBUTING.md) and [security reporting](SECURITY.md).
|
||||
|
||||
[简体中文](README.zh-CN.md) | English
|
||||
|
||||
PIGWay Frame Flow is a lightweight, self-hosted platform for programmable smart-frame automation. It runs independently on a NAS or server, with its own Web UI, image library, rendering, scheduler and REST API. KoKonna is a supported device integration; external applications do not need its credentials or SDK.
|
||||
@@ -47,7 +49,7 @@ Synology Photos API sources work without `/photos` or NFS mounts, with shared/cu
|
||||
- Seven templates: Daily Dashboard, Weather, Calendar, Quote, Photo + Text, Daily Poetry and System Alert.
|
||||
- Layout Studio for collages/posters with 1–12 images; optional OpenAI-compatible layout planning and source-driven automatic collages.
|
||||
- Device-bound schedules, ordered/random playlists, temporary priority overrides, restore and persistent operation history.
|
||||
- Read-only NAS folders, Synology Photos person filtering, WebDAV and optional cloud-drive connectors. Each source has its own folder and filter settings. People filtering uses one shared Synology Photos sign-in; WebDAV and cloud-drive credentials belong to their respective sources.
|
||||
- Synology Photos person filtering, WebDAV and optional cloud-drive connectors. Each source has its own folder and filter settings. People filtering uses one shared Synology Photos sign-in; WebDAV and cloud-drive credentials belong to their respective sources.
|
||||
- Optional weather, calendar, monitoring, AI, MQTT and webhook integrations. Provider configuration is required; an unconnected provider is not a working connection.
|
||||
|
||||
Templates **render images**, including text-only templates. Choose a template, edit its data, generate a preview, then display it. Preview generation and saving template settings do not update the frame. Photo + Text and Daily Dashboard can include a selected local photo; other templates do not automatically choose one. Scheduled template jobs render afresh on each run. See [photo sources](docs/PHOTO_SOURCES.md), [automatic collages](docs/AUTOMATIC_COLLAGE.md) and [integration setup/limits](docs/EXTENSIONS.md).
|
||||
|
||||
+3
-1
@@ -1,5 +1,7 @@
|
||||
# PIGWay Frame Flow
|
||||
|
||||
开发环境目前支持 Python 3.14.x。参见[贡献指南](CONTRIBUTING.md)和[安全问题报告](SECURITY.md)。
|
||||
|
||||
简体中文 | [English](README.md)
|
||||
|
||||
轻量、自托管的智能画框自动化平台,可独立运行在 NAS 或服务器上,提供自己的 Web 界面、图库、图片渲染、调度器和 REST API。KoKonna 是支持的设备集成之一;外部应用无需持有它的凭据或引入其 SDK。
|
||||
@@ -47,7 +49,7 @@ Synology Photos 可使用独立的 API 来源,无需 `/photos` 或 NFS 挂载
|
||||
- 七种模板:家庭早报、天气、日历、一句话、照片与文字、每日诗词、系统告警。
|
||||
- 拼图工作室支持 1–12 张图片的拼图与海报;可选 OpenAI 兼容接口排版,以及从数据源自动选图拼接。
|
||||
- 绑定设备的定时任务、顺序/随机播放列表、带优先级的临时覆盖、恢复与持久化操作历史。
|
||||
- 只读 NAS 文件夹、Synology Photos 人物筛选、WebDAV 和可选网盘连接器;每个数据源独立配置、独立授权。
|
||||
- Synology Photos 人物筛选、WebDAV 和可选网盘连接器;每个数据源独立配置、独立授权。
|
||||
- 可选天气、日历、监控、AI、MQTT 与 Webhook 集成。需要配置对应 Provider;尚未授权的数据源不会被当作已连接。
|
||||
|
||||
模板会**生成图片**,纯文字模板也是如此。使用顺序是:选择模板 → 编辑内容 → 生成预览 → 显示到画框。生成预览和保存模板设置都不会更新画框。“照片与文字”和“家庭早报”可以包含指定的本地照片,其他模板不会自动选图;定时模板任务每次运行会重新渲染。参见[照片数据源](docs/PHOTO_SOURCES.md)、[自动拼图](docs/AUTOMATIC_COLLAGE.md)和[集成配置及限制](docs/EXTENSIONS.md)。
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
# Security policy
|
||||
|
||||
Security fixes target the latest release. Older releases have no guaranteed
|
||||
backport support. Upgrade before verifying whether an issue is still present.
|
||||
|
||||
Do not publish credentials, private photos, production logs, or working exploit
|
||||
payloads in public issues. Contact the repository owner privately through the
|
||||
hosting platform when available. If no private contact channel is available,
|
||||
open an issue asking for a confidential reporting channel without technical
|
||||
vulnerability details. There is currently no dedicated security mailbox or
|
||||
promised response SLA.
|
||||
|
||||
A useful private report includes the affected version, deployment mode, required
|
||||
permissions, impact, and minimal steps using mock data. Do not test on another
|
||||
person's deployment or write to real frames without explicit authorization.
|
||||
+3
-1
@@ -4,7 +4,9 @@ Runtime keys, passwords, sessions, private photos, databases and local `.env` fi
|
||||
must remain outside Git. Examples use documentation-only addresses and identities.
|
||||
Personal deployment reports and screenshots are excluded from public history.
|
||||
|
||||
The NAS Docker runner accepts trusted repository events only. External fork PRs
|
||||
The Gitea NAS Docker runner accepts trusted repository events only. GitHub mirrors
|
||||
use the separate community workflow on GitHub-hosted disposable runners, with
|
||||
read-only repository permissions and no deployment configuration. External fork PRs
|
||||
are not executed on this runner; maintainers must review them before copying changes
|
||||
to a trusted branch. All lint, type, test, audit and isolated Docker checks remain.
|
||||
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
# Gitea Actions production CD v1
|
||||
# Gitea Actions production CD v1 (historical)
|
||||
|
||||
> This NAS production deployment procedure is retired. Current Gitea Actions
|
||||
> only runs isolated verification; production uses the maintainer-specific
|
||||
> Ubuntu workflow in `scripts/server-release.py`. For a new installation use
|
||||
> the Docker Compose instructions in README.md. Filesystem/NFS photo sources
|
||||
> are disabled; use Synology Photos API or WebDAV. The configuration below is
|
||||
> retained for historical reference and must not be used for new deployments.
|
||||
|
||||
## Audit and adoption boundary
|
||||
|
||||
|
||||
+3
-1
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "pigway-frame-flow"
|
||||
version = "0.1.17"
|
||||
requires-python = ">=3.12"
|
||||
requires-python = ">=3.14,<3.15"
|
||||
dependencies = ["paho-mqtt==2.1.0", "python-dateutil==2.9.0.post0", "fastapi==0.142.2", "uvicorn==0.54.0", "pillow==12.3.0", "requests==2.34.2", "croniter==6.2.4", "python-multipart==0.0.32", "pyyaml==6.0.3"]
|
||||
[project.optional-dependencies]
|
||||
test = ["pytest==9.1.1", "httpx2==2.13.1", "mypy==2.3.1", "pip-audit==2.10.1", "types-requests==2.33.0.20260906", "types-PyYAML==6.0.12.20260906", "types-croniter==6.2.4.20260711", "ruff==0.16.9"]
|
||||
@@ -9,6 +9,8 @@ test = ["pytest==9.1.1", "httpx2==2.13.1", "mypy==2.3.1", "pip-audit==2.10.1", "
|
||||
pythonpath = ["."]
|
||||
testpaths = ["tests"]
|
||||
[tool.ruff]
|
||||
# Preserve existing syntax/formatting independently of runtime support.
|
||||
target-version = "py312"
|
||||
exclude = ["vendor", ".venv"]
|
||||
[build-system]
|
||||
requires = ["setuptools>=75"]
|
||||
|
||||
@@ -34,3 +34,22 @@ def test_actions_downloads_do_not_depend_on_personal_server():
|
||||
r"https://github\.com/actions/(checkout|setup-python)@[0-9a-f]{40}",
|
||||
action,
|
||||
)
|
||||
|
||||
|
||||
def test_community_checks_are_isolated_from_private_runners():
|
||||
import yaml
|
||||
|
||||
private = yaml.safe_load(Path(".github/workflows/verify.yml").read_text())
|
||||
public = yaml.safe_load(Path(".github/workflows/community.yml").read_text())
|
||||
assert (
|
||||
"github.server_url != 'https://github.com'" in private["jobs"]["verify"]["if"]
|
||||
)
|
||||
job = public["jobs"]["verify"]
|
||||
assert job["if"] == "github.server_url == 'https://github.com'"
|
||||
assert job["runs-on"] == "ubuntu-latest"
|
||||
assert public["permissions"] == {"contents": "read"}
|
||||
workflow = Path(".github/workflows/community.yml").read_text()
|
||||
assert "secrets." not in workflow
|
||||
assert "production-deploy" not in workflow
|
||||
assert "pull_request_target" not in workflow
|
||||
assert "persist-credentials: false" in workflow
|
||||
|
||||
Reference in New Issue
Block a user