mirror of
https://github.com/wiltodelta/remove-ai-watermarks.git
synced 2026-10-14 05:20:46 +02:00
Scan uv.lock in CI and add a security policy
Add a CI job running the maintain.sh uv-secure scan, pinned to the gate by a parity test, and a SECURITY.md with private reporting and dependency remediation. Refresh the security-gate block record for accelerate 1.15.0. Closes #114 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
70adddf960
commit
72752feb33
6 files changed
+67
-9
No files matched your search
@@ -81,7 +81,8 @@ Run `bash maintain.sh` from the repository root. The authoritative type gate is
|
||||
|
||||
The security scanner's exit status is authoritative, including a failure after a success
|
||||
message. `tests/test_maintenance.py` checks clean, vulnerable, and broken scanner
|
||||
runs through the real shell entry point. Recheck unresolved advisories using the
|
||||
runs through the real shell entry point, and pins the CI `security` job to the
|
||||
same scanner line with no `continue-on-error`. Recheck unresolved advisories using the
|
||||
procedure in `docs/development.md`; do not revive the old text-matching bypass.
|
||||
|
||||
Boundary modules for cv2, Torch, and Diffusers may carry narrow per-file relaxations for unknown third-party types. Keep pure-logic files strict, preserve the local piexif stub, and fix real errors before widening a pragma.
|
||||
|
||||
@@ -29,6 +29,19 @@ jobs:
|
||||
- name: Ruff format check
|
||||
run: uv run ruff format --check
|
||||
|
||||
security:
|
||||
name: lockfile vulnerability scan
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: astral-sh/setup-uv@v7
|
||||
with:
|
||||
enable-cache: false
|
||||
# Policy and triaged blocks: docs/development.md "Known security-gate blocks".
|
||||
- name: Scan uv.lock with uv-secure
|
||||
run: uvx uv-secure uv.lock
|
||||
|
||||
test:
|
||||
name: test ${{ matrix.os }} py${{ matrix.python-version }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
@@ -571,7 +571,8 @@ bash maintain.sh
|
||||
```
|
||||
|
||||
See [module internals](docs/module-internals.md) before changing a subsystem
|
||||
with documented invariants.
|
||||
with documented invariants. Report vulnerabilities as described in
|
||||
[SECURITY.md](SECURITY.md).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
# Security policy
|
||||
|
||||
## Supported versions
|
||||
|
||||
Security fixes go into the latest release. Older releases are not patched;
|
||||
upgrade through the channel you installed from (PyPI or Homebrew).
|
||||
|
||||
## Reporting a vulnerability
|
||||
|
||||
Report vulnerabilities privately through
|
||||
[GitHub private vulnerability reporting](https://github.com/wiltodelta/remove-ai-watermarks/security/advisories/new).
|
||||
Do not open a public issue for an unpatched vulnerability. Include the affected
|
||||
version, the command or API call, and a minimal input that reproduces it.
|
||||
|
||||
Vulnerabilities in a dependency, such as a CVE in a package from `uv.lock`, can
|
||||
be reported as a regular issue when the advisory is already public.
|
||||
|
||||
## Dependency vulnerabilities
|
||||
|
||||
Dependabot raises alerts and update pull requests for `uv.lock` and GitHub
|
||||
Actions, and CI scans `uv.lock` with
|
||||
[`uv-secure`](https://github.com/owenlamont/uv-secure) on every push and pull
|
||||
request. A vulnerable dependency is upgraded to a fixed release; advisories
|
||||
without one are tracked under
|
||||
[Known security-gate blocks](docs/development.md#known-security-gate-blocks).
|
||||
+12
-6
@@ -29,7 +29,7 @@ Do not add advisory ignores or suppress the scanner's exit status. Run and
|
||||
report Ruff, Pyright scoped to `src/`, and tests separately when security blocks
|
||||
the gate.
|
||||
|
||||
Rechecked on 2026-09-10 against the locked versions and the advisory sources:
|
||||
Rechecked on 2026-10-02 against the locked versions and the advisory sources:
|
||||
|
||||
- `lightning` and `pytorch-lightning`, pulled by the optional `trustmark`
|
||||
extra, are pinned to 2.6.6. That release clears PYSEC-2026-3624 and
|
||||
@@ -37,18 +37,19 @@ Rechecked on 2026-09-10 against the locked versions and the advisory sources:
|
||||
- `accelerate`, required by the diffusion stack, is affected by
|
||||
[GHSA-4j2p-28q2-5m79](https://github.com/advisories/GHSA-4j2p-28q2-5m79)
|
||||
and PYSEC-2026-3804. The sharded-checkpoint loader accepts unsafe
|
||||
`weight_map` paths; neither advisory lists a patched release. 1.15.0 is
|
||||
on PyPI and is outside the advisory's `<= 1.14.0` range, but its
|
||||
`weight_map` paths; neither advisory lists a patched release. The lock
|
||||
carries 1.15.0, which is outside the advisory's `<= 1.14.0` range, so the
|
||||
scanner no longer blocks the gate. Its
|
||||
`load_checkpoint_in_model` still joins `weight_map` entries with no
|
||||
containment check, and the sanitizer PRs
|
||||
([#4138](https://github.com/huggingface/accelerate/pull/4138),
|
||||
[#4214](https://github.com/huggingface/accelerate/pull/4214)) did not
|
||||
land. Do not bump solely to silence the scanner. The project has no
|
||||
[#4214](https://github.com/huggingface/accelerate/pull/4214)) were closed
|
||||
without merging. Do not treat the passing scan as a fix. The project has no
|
||||
direct call to `load_checkpoint_in_model` or
|
||||
`load_checkpoint_and_dispatch`, but this does not prove indirect
|
||||
model-loading paths are unaffected.
|
||||
|
||||
Before carrying the remaining block forward, rerun `uvx uv-secure uv.lock` and check
|
||||
When a new block appears, or before carrying one forward, rerun `uvx uv-secure uv.lock` and check
|
||||
PyPI for a fixed release. Upgrade a fixed package with
|
||||
`uv lock --upgrade-package <package>` and rerun the gate. Removing the current
|
||||
dependency would remove a supported optional feature, so that is not a
|
||||
@@ -98,6 +99,11 @@ run the full-clip video test. Diffusion and model-running tests skip in that
|
||||
matrix; metadata, identification, visible removal, the DWT-DCT decoder, and the
|
||||
OpenCV eraser remain covered across operating systems.
|
||||
|
||||
A separate `security` job runs the `maintain.sh` lockfile scan, so an advisory
|
||||
without a released fix turns `main` red; see
|
||||
[Known security-gate blocks](#known-security-gate-blocks). Vulnerability
|
||||
reporting is described in [`SECURITY.md`](../SECURITY.md).
|
||||
|
||||
Keep `uv.lock` compatible with `uv sync --frozen`. Dependency pull-request checks use GitHub's merge result against current `main`; if `main` moves, merge it locally and rerun the full gate because a newer linter can expose stale directives in later code.
|
||||
|
||||
`test.yml` runs one concurrency group per ref with `cancel-in-progress: true`, so a newer push cancels the previous run mid-flight. A cancelled run is not a failure verdict: the superseding run's head includes the cancelled commits as ancestors, so watch that run to completion instead of retrying the push.
|
||||
|
||||
@@ -8,8 +8,10 @@ import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
|
||||
GATE = Path(__file__).resolve().parents[1] / "maintain.sh"
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
GATE = ROOT / "maintain.sh"
|
||||
BASH = shutil.which("bash")
|
||||
pytestmark = pytest.mark.skipif(os.name != "posix" or BASH is None, reason="The maintenance entry point requires Bash")
|
||||
|
||||
@@ -65,3 +67,13 @@ def test_security_exit_status_controls_the_gate(tmp_path, scanner_output, scanne
|
||||
else:
|
||||
assert result.returncode == 0
|
||||
assert calls[-1] == "uv run pytest -n auto"
|
||||
|
||||
|
||||
def test_ci_runs_the_gate_security_scan_unweakened():
|
||||
scan = next(line for line in GATE.read_text().splitlines() if line.startswith("uvx uv-secure"))
|
||||
workflow = yaml.safe_load((ROOT / ".github/workflows/test.yml").read_text())
|
||||
job = workflow["jobs"]["security"]
|
||||
runs = [step["run"].strip() for step in job["steps"] if "run" in step]
|
||||
assert runs == [scan]
|
||||
assert not job.get("continue-on-error")
|
||||
assert not any(step.get("continue-on-error") for step in job["steps"])
|
||||
Reference in new issue
Block a user