Security¶
Supply chain security¶
repomatic implements most of the practices described in Astral’s Open Source Security at Astral post, baked into a drop-in setup that any maintainer can inherit by pointing their workflows at the reusable callers.
Astral practice |
How |
|---|---|
Ban dangerous triggers ( |
The lint-workflow-security job runs |
Minimal workflow permissions |
|
Pinned actions |
All |
No force-pushes to |
|
Immutable release tags |
|
Dependency cooldowns |
Renovate stabilization windows ( |
Trusted Publishing |
PyPI uploads via |
Cryptographic attestations |
Every binary and wheel is attested to the workflow run that built it via |
Checksums in installer scripts |
The |
Fork PR approval policy |
|
Warning
Known gap: multi-person release approval. Astral gates releases behind a dedicated GitHub deployment environment with required reviewers, so that a single compromised account cannot publish. repomatic does not enforce this, but if the repository has multiple maintainers, I recommend adding an environment: release key to the publish-pypi and create-release jobs in a downstream caller workflow and configuring required reviewers on that environment in repo settings.
Permissions and token¶
Several workflows need a REPOMATIC_PAT secret to create PRs that modify files in .github/workflows/ and to trigger downstream workflows. Without it, those jobs silently fall back to the default GITHUB_TOKEN, which lacks the required permissions.
After your first push, the setup-guide job automatically opens an issue with step-by-step instructions to create and configure the token.
Concurrency and cancellation¶
All workflows use a concurrency directive to prevent redundant runs and save CI resources. When a new commit is pushed, any in-progress workflow runs for the same branch or PR are automatically cancelled.
Workflows are grouped by:
Pull requests:
{workflow-name}-{pr-number}— Multiple commits to the same PR cancel previous runsBranch pushes:
{workflow-name}-{branch-ref}— Multiple pushes to the same branch cancel previous runs
release.yaml uses a stronger protection: release commits get a unique concurrency group based on the commit SHA, so they can never be cancelled. This ensures tagging, PyPI publishing, and GitHub release creation complete successfully.
Additionally, cancel-runs.yaml actively cancels in-progress and queued runs when a PR is closed. This complements passive concurrency groups, which only trigger cancellation when a new run enters the same group — closing a PR doesn’t produce such an event.
Tip
For implementation details on how concurrency groups are computed and why release.yaml needs special handling, see the repomatic.github.actions module docstring.
AV false-positive submissions¶
Compiled Python binaries (built with Nuitka --onefile) are frequently flagged as malicious by heuristic AV engines. The onefile packaging technique (self-extracting archive with embedded Python runtime) triggers generic “packed/suspicious” signatures. This is a known issue across the Nuitka ecosystem.
The scan-virustotal job in release.yaml uploads all compiled binaries to VirusTotal on every release. This seeds AV vendor databases to reduce false positive rates for downstream distributors (Chocolatey, Scoop, etc.).
When a release is flagged, the /av-false-positive skill generates per-vendor submission files with pre-written text and form field mappings. The vendor details below document the process for manual reference.
Vendor portals¶
Vendor |
Engines covered |
Portal |
Format |
Turnaround |
|---|---|---|---|---|
Microsoft |
|
One file per form, 1900 char limit on additional info |
Fastest |
|
BitDefender |
|
One file per form, screenshot mandatory |
Fast |
|
ESET |
|
Email to |
Single email, password-protected ZIP ( |
Reliable |
Symantec |
|
Hash submission only (no |
3-7 business days |
|
Avast/AVG |
|
One file per form, shared engine |
Medium |
|
Sophos |
|
One file per form, 25 MB max per submission |
Up to 15 business days |
Submission priority¶
Submit in this order to maximize impact:
Microsoft: most influential engine. ML detections (
Sabsik,Wacatac) have the broadest downstream effect.BitDefender: powers ~6 downstream vendor engines. Highest detection-removal-per-submission ratio.
ESET: email-based channel with no portal dependency. The most reliable submission path.
Symantec: ML detections (
ML.Attribute.*) may take longer to process.Avast/AVG: shared engine, so one submission covers both.
Sophos: PUA detections require justification of the software’s legitimate purpose.
Submission content¶
Every false-positive submission should include:
The binary’s VirusTotal report link.
VirusTotal links for the clean
.whland.tar.gzsource distributions (as comparison evidence).The GitHub release link and direct download URL for the binary.
Project homepage and PyPI URL.
License from
pyproject.toml.Reference to any prior false-positive issue in the repository.
All submission text should mention that the binary is compiled with Nuitka --onefile from an open-source project.
Known portal issues¶
Microsoft: CORS errors or stuck progress modals during upload (auth session expiring). Workaround: sign out, clear cookies for
microsoft.com, sign back in, submit immediately.BitDefender: form sometimes returns “Your request could not be registered!” with no details. Retry later.
Avast: form sometimes returns “An internal error occurred while sending the form.” Retry later.