trivy-action checks its own repository out of github.com using the runner token; on this self-hosted Gitea that token is a Gitea token, GitHub answers "Bad credentials", and both scan steps die before trivy is installed. Download the v0.69.3 release archive directly, verify it against a sha256 digest pinned inline, and unpack only the binary into .release-work/bin, which is gitignored and excluded from the Docker build context. The gate keeps its exact semantics: --exit-code 1, --severity HIGH,CRITICAL, table output, unfixed vulnerabilities still in scope. The SPDX step writes the same filename release_artifacts.py normalize-container-sbom consumes, and TRIVY_CACHE_DIR keeps the vulnerability DB inside the work directory.