mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-30 20:54:32 +08:00
ci: 建立镜像发布前供应链门禁 (#6393)
This commit is contained in:
@@ -30,6 +30,17 @@ jobs:
|
||||
- name: Verify dependency lock
|
||||
run: uv lock --check
|
||||
|
||||
- name: Audit locked Python dependencies
|
||||
run: |
|
||||
uv export --quiet --locked --no-dev --no-emit-project \
|
||||
--output-file /tmp/moviepilot-audit-requirements.txt
|
||||
uvx --from pip-audit==2.10.1 pip-audit \
|
||||
--require-hashes \
|
||||
--disable-pip \
|
||||
--strict \
|
||||
--progress-spinner off \
|
||||
--requirement /tmp/moviepilot-audit-requirements.txt
|
||||
|
||||
- name: Release version
|
||||
id: release_version
|
||||
run: |
|
||||
@@ -127,6 +138,66 @@ jobs:
|
||||
- name: Set Up Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build amd64 candidate
|
||||
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
|
||||
with:
|
||||
context: .
|
||||
file: docker/Dockerfile
|
||||
platforms: linux/amd64
|
||||
load: true
|
||||
push: false
|
||||
pull: true
|
||||
tags: moviepilot-v3-candidate:linux-amd64
|
||||
build-args: |
|
||||
MOVIEPILOT_FRONTEND_VERSION=${{ steps.release_version.outputs.frontend_version }}
|
||||
MOVIEPILOT_FRONTEND_SHA256=${{ steps.payloads.outputs.frontend_sha256 }}
|
||||
MOVIEPILOT_PLUGINS_REF=${{ steps.payloads.outputs.plugins_revision }}
|
||||
MOVIEPILOT_RESOURCES_REF=${{ steps.payloads.outputs.resources_revision }}
|
||||
cache-from: type=gha,scope=moviepilot-v3-docker-amd64,version=2
|
||||
cache-to: type=gha,scope=moviepilot-v3-docker-amd64,mode=max,version=2
|
||||
|
||||
- name: Scan amd64 candidate vulnerabilities
|
||||
uses: aquasecurity/trivy-action@a9c7b0f06e461e9d4b4d1711f154ee024b8d7ab8 # v0.36.0
|
||||
with:
|
||||
image-ref: moviepilot-v3-candidate:linux-amd64
|
||||
version: v0.70.0
|
||||
scanners: vuln
|
||||
vuln-type: os,library
|
||||
severity: HIGH,CRITICAL
|
||||
ignore-unfixed: true
|
||||
trivyignores: .trivyignore.yaml
|
||||
exit-code: 1
|
||||
|
||||
- name: Build arm64 candidate
|
||||
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
|
||||
with:
|
||||
context: .
|
||||
file: docker/Dockerfile
|
||||
platforms: linux/arm64/v8
|
||||
load: true
|
||||
push: false
|
||||
pull: true
|
||||
tags: moviepilot-v3-candidate:linux-arm64
|
||||
build-args: |
|
||||
MOVIEPILOT_FRONTEND_VERSION=${{ steps.release_version.outputs.frontend_version }}
|
||||
MOVIEPILOT_FRONTEND_SHA256=${{ steps.payloads.outputs.frontend_sha256 }}
|
||||
MOVIEPILOT_PLUGINS_REF=${{ steps.payloads.outputs.plugins_revision }}
|
||||
MOVIEPILOT_RESOURCES_REF=${{ steps.payloads.outputs.resources_revision }}
|
||||
cache-from: type=gha,scope=moviepilot-v3-docker-arm64,version=2
|
||||
cache-to: type=gha,scope=moviepilot-v3-docker-arm64,mode=max,version=2
|
||||
|
||||
- name: Scan arm64 candidate vulnerabilities
|
||||
uses: aquasecurity/trivy-action@a9c7b0f06e461e9d4b4d1711f154ee024b8d7ab8 # v0.36.0
|
||||
with:
|
||||
image-ref: moviepilot-v3-candidate:linux-arm64
|
||||
version: v0.70.0
|
||||
scanners: vuln
|
||||
vuln-type: os,library
|
||||
severity: HIGH,CRITICAL
|
||||
ignore-unfixed: true
|
||||
trivyignores: .trivyignore.yaml
|
||||
exit-code: 1
|
||||
|
||||
- name: Login DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
@@ -140,8 +211,8 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build Image
|
||||
uses: docker/build-push-action@v7
|
||||
- name: Publish multi-architecture image
|
||||
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
|
||||
with:
|
||||
context: .
|
||||
file: docker/Dockerfile
|
||||
@@ -149,6 +220,7 @@ jobs:
|
||||
linux/amd64
|
||||
linux/arm64/v8
|
||||
push: true
|
||||
pull: false
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
build-args: |
|
||||
MOVIEPILOT_FRONTEND_VERSION=${{ steps.release_version.outputs.frontend_version }}
|
||||
@@ -166,8 +238,9 @@ jobs:
|
||||
org.moviepilot.resources-revision=${{ steps.payloads.outputs.resources_revision }}
|
||||
org.moviepilot.plugin-market-wiki-revision=${{ steps.plugin_market.outputs.wiki_commit }}
|
||||
org.moviepilot.models-catalog-digest=${{ steps.models_catalog.outputs.digest }}
|
||||
cache-from: type=gha,scope=moviepilot-v3-docker,version=2
|
||||
cache-to: type=gha,scope=moviepilot-v3-docker,mode=max,version=2
|
||||
cache-from: |
|
||||
type=gha,scope=moviepilot-v3-docker-amd64,version=2
|
||||
type=gha,scope=moviepilot-v3-docker-arm64,version=2
|
||||
|
||||
- name: Generate Changelog
|
||||
id: changelog
|
||||
|
||||
@@ -9,7 +9,6 @@ dist/
|
||||
rust/**/target/
|
||||
nginx/
|
||||
test.py
|
||||
safety_report.txt
|
||||
app/application/site/*.bin
|
||||
# 站点数据的运行期下载产物。上游 v3 架构重构后落点从 app/application/site 移到了
|
||||
# app/helper,同目录的 .so/.pyd 由上面的通配兜住,只有 .bin 漏了网
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
vulnerabilities:
|
||||
- id: GHSA-6v7p-g79w-8964
|
||||
paths:
|
||||
- Python
|
||||
purls:
|
||||
- pkg:pypi/msgpack@1.1.2
|
||||
statement: The finding belongs to the base image's system pip and is not imported by MoviePilot.
|
||||
- id: CVE-2025-47273
|
||||
paths:
|
||||
- Python
|
||||
purls:
|
||||
- pkg:pypi/setuptools@70.3.0
|
||||
statement: The finding belongs to the base image's system pip and is not used for dependency installation.
|
||||
- id: CVE-2026-33818
|
||||
paths:
|
||||
- usr/bin/rclone
|
||||
purls:
|
||||
- pkg:golang/stdlib@v1.26.5
|
||||
statement: The official rclone binary has no patched release for this embedded Go runtime yet.
|
||||
- id: CVE-2026-39821
|
||||
paths:
|
||||
- usr/bin/rclone
|
||||
purls:
|
||||
- pkg:golang/stdlib@v1.26.5
|
||||
statement: The official rclone binary has no patched release for this embedded Go runtime yet.
|
||||
- id: CVE-2026-46600
|
||||
paths:
|
||||
- usr/bin/rclone
|
||||
purls:
|
||||
- pkg:golang/stdlib@v1.26.5
|
||||
statement: The official rclone binary has no patched release for this embedded Go runtime yet.
|
||||
- id: CVE-2026-56853
|
||||
paths:
|
||||
- usr/bin/rclone
|
||||
purls:
|
||||
- pkg:golang/stdlib@v1.26.5
|
||||
statement: The official rclone binary has no patched release for this embedded Go runtime yet.
|
||||
- id: CVE-2026-56858
|
||||
paths:
|
||||
- usr/bin/rclone
|
||||
purls:
|
||||
- pkg:golang/stdlib@v1.26.5
|
||||
statement: The official rclone binary has no patched release for this embedded Go runtime yet.
|
||||
- id: CVE-2026-56859
|
||||
paths:
|
||||
- usr/bin/rclone
|
||||
purls:
|
||||
- pkg:golang/stdlib@v1.26.5
|
||||
statement: The official rclone binary has no patched release for this embedded Go runtime yet.
|
||||
- id: CVE-2026-56860
|
||||
paths:
|
||||
- usr/bin/rclone
|
||||
purls:
|
||||
- pkg:golang/stdlib@v1.26.5
|
||||
statement: The official rclone binary has no patched release for this embedded Go runtime yet.
|
||||
- id: CVE-2026-56862
|
||||
paths:
|
||||
- usr/bin/rclone
|
||||
purls:
|
||||
- pkg:golang/stdlib@v1.26.5
|
||||
statement: The official rclone binary has no patched release for this embedded Go runtime yet.
|
||||
@@ -38,7 +38,7 @@ For work that changes or reviews repository behavior, identify the domains actua
|
||||
|
||||
### Quality and Security
|
||||
* **Primary Reference:** `docs/rules/11-quality-and-security.md`
|
||||
* **Required Constraints:** All code changes must pass the relevant pytest tests and pylint checks. Dependency changes require a current `uv.lock`, locked environment verification, and a passing manual Safety scan.
|
||||
* **Required Constraints:** All code changes must pass the relevant pytest tests and pylint checks. Dependency changes require a current `uv.lock`, locked environment verification, and a passing locked dependency vulnerability audit.
|
||||
|
||||
### Testing
|
||||
* **Primary Reference:** `docs/testing.md`
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ FROM rclone/rclone:1.75.0@sha256:b06aed988cf5967de7c25be5925240983981c757f4ed1ac
|
||||
FROM mwader/static-ffmpeg:8.1.1@sha256:735f84b905e00d5c618b667f0b053f83b1096f5fc404c607e6134bf2275a0e0a AS ffmpeg
|
||||
|
||||
|
||||
FROM python:3.14.7-slim-trixie@sha256:ce40764625a4ff50df3548277632e7f96c4e77fe75fa848aae9885476e7df5a4 AS base
|
||||
FROM python:3.14.7-slim-trixie AS base
|
||||
|
||||
|
||||
# 准备外部制品所需的最小工具集
|
||||
@@ -38,7 +38,6 @@ ENV LANG="C.UTF-8" \
|
||||
ENV PATH="${VENV_PATH}/bin:${PATH}"
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get upgrade -y \
|
||||
&& apt-get install -y --no-install-recommends ca-certificates curl \
|
||||
&& install -d -m 0755 /usr/share/postgresql-common/pgdg \
|
||||
&& curl -fsSL \
|
||||
@@ -77,6 +76,7 @@ RUN apt-get update \
|
||||
openssh-client \
|
||||
sshpass \
|
||||
iproute2 \
|
||||
util-linux \
|
||||
netcat-openbsd \
|
||||
lsof \
|
||||
nano \
|
||||
|
||||
+11
-11
@@ -150,20 +150,20 @@ python -m scripts.generate_plugin_market_default \
|
||||
--config-file app/runtime/config.py
|
||||
```
|
||||
|
||||
### 5. 运行安全检查
|
||||
### 5. 运行依赖漏洞检查
|
||||
|
||||
我们使用 `safety` 工具检查 `pyproject.toml` 与 `uv.lock` 中是否存在已知安全漏洞。该检查是
|
||||
依赖变更的人工门禁,当前不属于自动 CI。
|
||||
|
||||
#### 执行安全检查
|
||||
|
||||
可以通过 `uvx` 在隔离工具环境中运行 `safety`,无需把它加入主程序依赖:
|
||||
正式发布会使用固定版本的 `pip-audit` 检查 `uv.lock` 锁定的运行时依赖。依赖变更后也可以在
|
||||
本地执行同一检查:
|
||||
|
||||
```bash
|
||||
uvx safety scan --target . --policy-file safety.policy.yml
|
||||
uv export --quiet --locked --no-dev --no-emit-project \
|
||||
--output-file /tmp/moviepilot-audit-requirements.txt
|
||||
uvx --from pip-audit==2.10.1 pip-audit \
|
||||
--require-hashes --disable-pip --strict --progress-spinner off \
|
||||
--requirement /tmp/moviepilot-audit-requirements.txt
|
||||
```
|
||||
|
||||
Safety 直接识别项目清单和锁文件,不需要生成或维护 requirements 文件。
|
||||
导出文件由 `uv.lock` 生成且保留哈希,不作为项目依赖清单提交。
|
||||
|
||||
### 6. 提交代码前的检查
|
||||
|
||||
@@ -171,7 +171,7 @@ Safety 直接识别项目清单和锁文件,不需要生成或维护 requireme
|
||||
|
||||
1. **确认依赖分层正确**:运行时包进入 `[project].dependencies`;测试、覆盖率、静态检查和构建辅助进入 `[dependency-groups].dev`;插件依赖不并入主程序运行时依赖。
|
||||
|
||||
2. **运行安全检查**:确保 `safety` 检查通过,没有新的安全漏洞。
|
||||
2. **运行依赖漏洞检查**:确保锁定的运行时依赖通过 `pip-audit`。
|
||||
|
||||
3. **运行测试**:如果项目中包含测试,请确保所有测试都通过。运行以下命令以执行测试:
|
||||
|
||||
@@ -202,6 +202,6 @@ Safety 直接识别项目清单和锁文件,不需要生成或维护 requireme
|
||||
### 7. 参考资源
|
||||
|
||||
- [uv 官方文档](https://docs.astral.sh/uv/)
|
||||
- [Safety CLI 官方文档](https://docs.safetycli.com/)
|
||||
- [pip-audit](https://github.com/pypa/pip-audit)
|
||||
- [MoviePilot-Resources](https://github.com/jxxghp/MoviePilot-Resources)
|
||||
- [MoviePilot-Plugins](https://github.com/jxxghp/MoviePilot-Plugins)
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
| pytest | Test runner | `uv run --locked --no-sync pytest tests/test_xxx.py` |
|
||||
| pylint | Static analysis | `uv run --locked --no-sync pylint app/` |
|
||||
| uv | Lock and environment consistency | `uv lock --check && uv pip check` |
|
||||
| safety | Manual dependency vulnerability scan | `uvx safety scan --target . --policy-file safety.policy.yml` |
|
||||
| pip-audit | Locked dependency vulnerability scan | `uv export --quiet --locked --no-dev --no-emit-project -o /tmp/moviepilot-audit-requirements.txt && uvx --from pip-audit==2.10.1 pip-audit --require-hashes --disable-pip --strict --progress-spinner off -r /tmp/moviepilot-audit-requirements.txt` |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -79,13 +79,16 @@ uv run --locked --no-sync pylint app/chain/download.py
|
||||
## Security Scan
|
||||
|
||||
```bash
|
||||
# Scan pyproject.toml and uv.lock
|
||||
uvx safety scan --target . --policy-file=safety.policy.yml
|
||||
uv export --quiet --locked --no-dev --no-emit-project \
|
||||
--output-file /tmp/moviepilot-audit-requirements.txt
|
||||
uvx --from pip-audit==2.10.1 pip-audit \
|
||||
--require-hashes --disable-pip --strict --progress-spinner off \
|
||||
--requirement /tmp/moviepilot-audit-requirements.txt
|
||||
```
|
||||
|
||||
**Rules:**
|
||||
- Run manually after runtime or development dependency changes; this is not currently an automated CI job.
|
||||
- No new high-severity vulnerabilities may be introduced.
|
||||
- Run after runtime dependency changes; the release workflow enforces the same audit before publishing images.
|
||||
- Any Python vulnerability reported by this audit blocks publishing until the dependency or explicit audit policy is updated.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -54,12 +54,17 @@ uv run --locked --no-sync pylint app/
|
||||
## Dependency Security Scan
|
||||
|
||||
```bash
|
||||
uvx safety scan --target . --policy-file safety.policy.yml
|
||||
uv export --quiet --locked --no-dev --no-emit-project \
|
||||
--output-file /tmp/moviepilot-audit-requirements.txt
|
||||
uvx --from pip-audit==2.10.1 pip-audit \
|
||||
--require-hashes --disable-pip --strict --progress-spinner off \
|
||||
--requirement /tmp/moviepilot-audit-requirements.txt
|
||||
```
|
||||
|
||||
- Run manually after runtime or development dependency changes; Safety scans `pyproject.toml` and `uv.lock` directly, and this check is not currently an automated CI job.
|
||||
- No new high-severity vulnerabilities may be introduced.
|
||||
- If a vulnerability cannot be patched immediately, document it explicitly in the PR description.
|
||||
- Run after runtime dependency changes; the release workflow audits the same locked dependency set before publishing images.
|
||||
- Any Python vulnerability reported by this audit blocks publishing until the dependency or explicit audit policy is updated.
|
||||
- Release candidates also scan OS and language packages on amd64 and arm64. HIGH or CRITICAL findings with an available fix block publishing; unfixed upstream findings require a separate reachability and impact assessment.
|
||||
- If upstream has no fix, assess reachability and impact before changing the audit policy; PR documentation alone does not bypass the gate.
|
||||
|
||||
---
|
||||
|
||||
@@ -131,7 +136,7 @@ Before marking any task as complete:
|
||||
|
||||
- [ ] Related pytest tests pass
|
||||
- [ ] No new pylint error-level issues in `pylint app/`
|
||||
- [ ] If dependencies changed: the package is in the correct `pyproject.toml` group, `uv.lock` is current, locked sync and `uv pip check` pass, and the manual Safety scan passes
|
||||
- [ ] If dependencies changed: the package is in the correct `pyproject.toml` group, `uv.lock` is current, locked sync and `uv pip check` pass, and the locked runtime dependency audit passes
|
||||
- [ ] If CLI behavior changed: `docs/cli.md` and related tests are updated
|
||||
- [ ] If MCP/API behavior changed: `docs/mcp-api.md` and related skill files are updated
|
||||
- [ ] If database schema changed: a new Alembic migration exists under `database/versions/`
|
||||
|
||||
@@ -103,7 +103,7 @@ When updating a dependency:
|
||||
|
||||
1. Decide the dependency layer: runtime packages go to `[project].dependencies`; test, coverage, lint, and explicit build tooling go to `[dependency-groups].dev`.
|
||||
2. Run `uv lock`, commit the updated `uv.lock`, and verify it with `uv lock --check`.
|
||||
3. Run `uv sync --locked`, `uv pip check`, and the manual `uvx safety scan --target . --policy-file safety.policy.yml` check.
|
||||
3. Run `uv sync --locked`, `uv pip check`, and the locked runtime dependency audit documented in `03-commands.md`.
|
||||
4. Run the full test suite: `uv run --locked --no-sync pytest`.
|
||||
|
||||
---
|
||||
|
||||
@@ -56,7 +56,7 @@ This repository maintains a structured documentation library covering the full d
|
||||
|
||||
* **11 Code Quality and Security**
|
||||
* File: `11-quality-and-security.md`
|
||||
* Scope: Testing requirements, pylint gates, safety scans, authentication patterns, and input validation rules.
|
||||
* Scope: Testing requirements, pylint gates, dependency vulnerability scans, authentication patterns, and input validation rules.
|
||||
|
||||
* **12 Collaboration, Versioning, Build, and Release**
|
||||
* File: `12-collaboration-and-distribution.md`
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
security:
|
||||
ignore-unpinned-requirements: False
|
||||
ignore-vulnerabilities:
|
||||
70612:
|
||||
reason: The official statement indicates that this vulnerability is not valid because users should use sandboxing when handling untrusted templates.
|
||||
65532:
|
||||
reason: Legacy issue related to tvdbapi usage.
|
||||
40100:
|
||||
reason: Legacy issue related to tvdbapi usage.
|
||||
68094:
|
||||
reason: This vulnerability is resolved by upgrading `python-multipart` to version 0.0.9.
|
||||
65293:
|
||||
reason: This vulnerability is resolved by upgrading `python-multipart` to version 0.0.9.
|
||||
64930:
|
||||
reason: This vulnerability is resolved by upgrading `python-multipart` to version 0.0.9.
|
||||
@@ -11,7 +11,7 @@ def test_runtime_image_installs_postgresql_18_client_from_pgdg() -> None:
|
||||
).read_text(encoding="utf-8")
|
||||
|
||||
assert re.search(
|
||||
r"^FROM python:[^\s]+-slim-trixie@sha256:[0-9a-f]{64} AS base$",
|
||||
r"^FROM python:3\.14\.7-slim-trixie AS base$",
|
||||
dockerfile,
|
||||
re.MULTILINE,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
"""正式镜像发布的供应链门禁合同。"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from ruamel.yaml import YAML
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
DOCKERFILE = ROOT / "docker" / "Dockerfile"
|
||||
RELEASE_WORKFLOW = ROOT / ".github" / "workflows" / "build-v3.yml"
|
||||
|
||||
|
||||
def _load_workflow() -> dict:
|
||||
"""以 YAML 1.2 解析正式发布工作流。"""
|
||||
yaml = YAML(typ="safe")
|
||||
return yaml.load(RELEASE_WORKFLOW.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def _steps_by_name(workflow: dict) -> dict[str, dict]:
|
||||
"""按名称索引发布步骤,顺序仍由原列表校验。"""
|
||||
return {
|
||||
step["name"]: step
|
||||
for step in workflow["jobs"]["Docker-build"]["steps"]
|
||||
if "name" in step
|
||||
}
|
||||
|
||||
|
||||
def test_base_image_uses_refreshable_tag_and_apt_does_not_upgrade_in_place() -> None:
|
||||
"""基础镜像允许获得上游更新,构建阶段不得无边界升级整套 Debian。"""
|
||||
dockerfile = DOCKERFILE.read_text(encoding="utf-8")
|
||||
|
||||
assert "FROM python:3.14.7-slim-trixie AS base" in dockerfile
|
||||
assert "python:3.14.7-slim-trixie@sha256:" not in dockerfile
|
||||
assert "apt-get upgrade" not in dockerfile
|
||||
assert "\n util-linux \\\n" in dockerfile
|
||||
|
||||
|
||||
def test_release_audits_locked_runtime_dependencies_before_building() -> None:
|
||||
"""发布构建前必须审计带哈希的锁定运行时依赖。"""
|
||||
workflow = _load_workflow()
|
||||
steps = workflow["jobs"]["Docker-build"]["steps"]
|
||||
names = [step.get("name") for step in steps]
|
||||
audit = _steps_by_name(workflow)["Audit locked Python dependencies"]["run"]
|
||||
|
||||
assert names.index("Audit locked Python dependencies") < names.index("Build amd64 candidate")
|
||||
assert "uv export --quiet --locked --no-dev --no-emit-project" in audit
|
||||
assert "pip-audit==2.10.1" in audit
|
||||
for option in ("--require-hashes", "--disable-pip", "--strict"):
|
||||
assert option in audit
|
||||
|
||||
|
||||
def test_release_scans_both_architectures_before_registry_login_and_publish() -> None:
|
||||
"""任一架构的最终漏洞扫描失败时都不得登录仓库或发布镜像。"""
|
||||
workflow = _load_workflow()
|
||||
steps = workflow["jobs"]["Docker-build"]["steps"]
|
||||
names = [step.get("name") for step in steps]
|
||||
indexed = _steps_by_name(workflow)
|
||||
|
||||
expected_candidates = {
|
||||
"Build amd64 candidate": ("linux/amd64", "moviepilot-v3-candidate:linux-amd64"),
|
||||
"Build arm64 candidate": ("linux/arm64/v8", "moviepilot-v3-candidate:linux-arm64"),
|
||||
}
|
||||
for name, (platform, tag) in expected_candidates.items():
|
||||
build = indexed[name]["with"]
|
||||
assert build["platforms"] == platform
|
||||
assert build["load"] is True
|
||||
assert build["push"] is False
|
||||
assert build["tags"] == tag
|
||||
assert build["pull"] is True
|
||||
assert "no-cache-filters" not in build
|
||||
|
||||
for name in (
|
||||
"Scan amd64 candidate vulnerabilities",
|
||||
"Scan arm64 candidate vulnerabilities",
|
||||
):
|
||||
scan = indexed[name]
|
||||
assert scan["uses"] == (
|
||||
"aquasecurity/trivy-action@"
|
||||
"a9c7b0f06e461e9d4b4d1711f154ee024b8d7ab8"
|
||||
)
|
||||
assert scan["with"].items() >= {
|
||||
"version": "v0.70.0",
|
||||
"scanners": "vuln",
|
||||
"vuln-type": "os,library",
|
||||
"severity": "HIGH,CRITICAL",
|
||||
"ignore-unfixed": True,
|
||||
"trivyignores": ".trivyignore.yaml",
|
||||
"exit-code": 1,
|
||||
}.items()
|
||||
|
||||
last_scan = names.index("Scan arm64 candidate vulnerabilities")
|
||||
assert last_scan < names.index("Login DockerHub")
|
||||
assert last_scan < names.index("Login GitHub Container Registry")
|
||||
assert last_scan < names.index("Publish multi-architecture image")
|
||||
|
||||
|
||||
def test_publish_reuses_scanned_architecture_caches_without_refreshing_base() -> None:
|
||||
"""发布构建复用已扫描候选缓存,不得在扫描后重新拉取未审计基础镜像。"""
|
||||
workflow = _load_workflow()
|
||||
publish = _steps_by_name(workflow)["Publish multi-architecture image"]["with"]
|
||||
|
||||
assert workflow["on"]["workflow_dispatch"] is None
|
||||
assert publish["platforms"] == "linux/amd64\nlinux/arm64/v8\n"
|
||||
assert publish["push"] is True
|
||||
assert publish["pull"] is False
|
||||
assert "scope=moviepilot-v3-docker-amd64" in publish["cache-from"]
|
||||
assert "scope=moviepilot-v3-docker-arm64" in publish["cache-from"]
|
||||
Reference in New Issue
Block a user