ci: pin actions to commit SHAs, guard Docker jobs from forks, scan the image, gate publish on security (SEC-06, SEC-07, SEC-14, SEC-15, SEC-16)
This commit is contained in:
1 parent
6f7a3c0e5b
commit
766968fa42
9 files changed
+679
-60
No files matched your search
@@ -2,9 +2,10 @@ name: publish
|
||||
|
||||
# Build the Python package with uv and publish it to the self-hosted Gitea PyPI
|
||||
# registry on merge. dev -> a dev package (aegis-gitea-mcp-dev, .devN versions);
|
||||
# main -> the stable package (aegis-gitea-mcp). Gated on lint + tests so a release
|
||||
# can never ship red. Reuses the REGISTRY_TOKEN package secret (same one ci.yml
|
||||
# uses); if it is absent the job fails loudly instead of publishing anonymously.
|
||||
# main -> the stable package (aegis-gitea-mcp). Gated on lint, tests and the security
|
||||
# checks so a release can never ship red. Reuses the REGISTRY_TOKEN package secret
|
||||
# (same one ci.yml uses); if it is absent the job fails loudly instead of publishing
|
||||
# anonymously.
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
@@ -19,13 +20,15 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
- name: Set up uv
|
||||
uses: astral-sh/setup-uv@v5
|
||||
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
|
||||
with:
|
||||
version: "0.12.5"
|
||||
enable-cache: false
|
||||
@@ -44,13 +47,15 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
- name: Set up uv
|
||||
uses: astral-sh/setup-uv@v5
|
||||
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
|
||||
with:
|
||||
version: "0.12.5"
|
||||
enable-cache: false
|
||||
@@ -60,7 +65,46 @@ jobs:
|
||||
run: uv run pytest
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 3. Build with uv and publish to the Gitea PyPI registry.
|
||||
# 3. Security: the same gates as ci.yml (secret scan over the history, security
|
||||
# tests, dependency audit, bandit rules). Nothing is published without them.
|
||||
# ---------------------------------------------------------------------------
|
||||
security:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
- name: Set up uv
|
||||
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
|
||||
with:
|
||||
version: "0.12.5"
|
||||
enable-cache: false
|
||||
- name: Install dependencies
|
||||
run: uv sync --locked
|
||||
- name: Install gitleaks
|
||||
shell: bash
|
||||
run: |
|
||||
bin_dir="${RUNNER_TEMP:-/tmp}/gitleaks-bin"
|
||||
bash scripts/ci/install_gitleaks.sh "${bin_dir}"
|
||||
echo "${bin_dir}" >> "$GITHUB_PATH"
|
||||
- name: Scan history
|
||||
shell: bash
|
||||
run: gitleaks git --config .gitleaks.toml --redact --no-banner --verbose --exit-code 1 .
|
||||
- name: Security tests
|
||||
run: uv run pytest tests/security --no-cov
|
||||
- name: Dependency audit
|
||||
run: bash scripts/ci/pip_audit.sh
|
||||
- name: Ruff security rules
|
||||
run: uv run ruff check --select S .
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 4. Build with uv and publish to the Gitea PyPI registry.
|
||||
#
|
||||
# dev -> aegis-gitea-mcp-dev X.Y.Z.dev<run_number> (always unique)
|
||||
# main -> aegis-gitea-mcp X.Y.Z (no-op if already there)
|
||||
@@ -70,19 +114,21 @@ jobs:
|
||||
# and version "X.Y.Z".
|
||||
# ---------------------------------------------------------------------------
|
||||
publish:
|
||||
needs: [lint, test]
|
||||
needs: [lint, test, security]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Set up uv
|
||||
uses: astral-sh/setup-uv@v5
|
||||
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
|
||||
with:
|
||||
version: "0.12.5"
|
||||
enable-cache: false
|
||||
@@ -135,7 +181,7 @@ jobs:
|
||||
# v4 artifact backend. The real deliverable is published to the registry
|
||||
# below, so a failed artifact upload must not fail the release.
|
||||
continue-on-error: true
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: dist-${{ steps.chan.outputs.channel }}
|
||||
path: dist/*
|
||||
@@ -144,25 +190,26 @@ jobs:
|
||||
shell: bash
|
||||
env:
|
||||
# Reuse the existing package secret (same one ci.yml uses). The
|
||||
# token authenticates as its owning Gitea user, so GITHUB_ACTOR is the
|
||||
# username and the token is the password.
|
||||
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
||||
# token authenticates as its owning Gitea user, so the actor is the
|
||||
# username and the token is the password. uv reads the credentials from these variables, so the token never
|
||||
# appears on a command line (process listings, shell traces).
|
||||
UV_PUBLISH_USERNAME: ${{ github.actor }}
|
||||
UV_PUBLISH_PASSWORD: ${{ secrets.REGISTRY_TOKEN }}
|
||||
run: |
|
||||
# --check-url makes uv skip files already in the registry, so a main
|
||||
# push that did not bump the version is a clean no-op instead of a 409.
|
||||
uv publish \
|
||||
--publish-url https://git.hiddenden.cafe/api/packages/Hiddenden/pypi \
|
||||
--check-url https://git.hiddenden.cafe/api/packages/Hiddenden/pypi/simple/ \
|
||||
--username "${GITHUB_ACTOR}" \
|
||||
--password "${REGISTRY_TOKEN}"
|
||||
--check-url https://git.hiddenden.cafe/api/packages/Hiddenden/pypi/simple/
|
||||
|
||||
# Optional second step to also publish to public PyPI lives behind its own
|
||||
# secret. Intentionally left as a disabled stub — this pass does NOT push
|
||||
# secret. Intentionally left as a disabled stub: this pass does NOT push
|
||||
# to public PyPI.
|
||||
#
|
||||
# - name: Publish to public PyPI
|
||||
# if: ${{ secrets.PYPI_TOKEN != '' }}
|
||||
# shell: bash
|
||||
# env:
|
||||
# PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
|
||||
# run: uv publish --username __token__ --password "${PYPI_TOKEN}"
|
||||
# UV_PUBLISH_USERNAME: __token__
|
||||
# UV_PUBLISH_PASSWORD: ${{ secrets.PYPI_TOKEN }}
|
||||
# run: uv publish
|
||||
Reference in new issue
Block a user