diff --git a/.github/workflows/ci-docs.yml b/.github/workflows/ci-docs.yml index 0acb531..88ee1d1 100644 --- a/.github/workflows/ci-docs.yml +++ b/.github/workflows/ci-docs.yml @@ -1,8 +1,8 @@ name: "CI: Build and Deploy Sphinx Documentation" on: - # pull_request: - # branches: [master] + pull_request: + branches: [master] push: branches: [master] release: @@ -17,8 +17,8 @@ defaults: shell: bash concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true + group: pages + cancel-in-progress: false jobs: build: @@ -44,26 +44,28 @@ jobs: enable-cache: true cache-dependency-glob: "**/pyproject.toml" - - name: Configure Pages - # if: github.event_name == 'release' - uses: actions/configure-pages@v5.0.0 - - name: Build docs run: | set -euo pipefail - uv run --extra docs sphinx-build -M html docs/source docs/build + uv run --group docs sphinx-build -M html docs/source docs/build --fail-on-warning touch docs/build/html/.nojekyll + + - name: Configure Pages + if: github.event_name == 'release' || github.event_name == 'workflow_dispatch' + uses: actions/configure-pages@v5.0.0 + - name: Upload Pages artifact - # if: github.event_name == 'release' + if: github.event_name == 'release' || github.event_name == 'workflow_dispatch' uses: actions/upload-pages-artifact@v4.0.0 with: path: docs/build/html deploy: name: Deploy docs - # REVISIT: documentation should be updated on all push events - # if: github.event_name == 'release' + if: github.event_name == 'release' || github.event_name == 'workflow_dispatch' needs: build + runs-on: ubuntu-latest + timeout-minutes: 10 permissions: pages: write @@ -73,8 +75,7 @@ jobs: name: github-pages url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 \ No newline at end of file + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/ci-lint.yml b/.github/workflows/ci-lint.yml index debe02f..3c78813 100644 --- a/.github/workflows/ci-lint.yml +++ b/.github/workflows/ci-lint.yml @@ -16,7 +16,7 @@ defaults: concurrency: group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true + cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: lint: @@ -45,9 +45,9 @@ jobs: - name: Run Ruff run: | set -euo pipefail - uv run --extra dev ruff check . + uv run --group dev ruff check . - name: Run Ruff formatter check run: | set -euo pipefail - uv run --extra dev ruff format --check . \ No newline at end of file + uv run --group dev ruff format --check . \ No newline at end of file diff --git a/.github/workflows/ci-test.yml b/.github/workflows/ci-test.yml index a551279..e6befb0 100644 --- a/.github/workflows/ci-test.yml +++ b/.github/workflows/ci-test.yml @@ -16,7 +16,7 @@ defaults: concurrency: group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true + cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: test: @@ -57,4 +57,4 @@ jobs: - name: Run test suite run: | set -euo pipefail - uv run --extra dev pytest + uv run --group dev pytest --tb=short -q diff --git a/.github/workflows/wheel-publish.yml b/.github/workflows/wheel-publish.yml index 0ade7ca..adae191 100644 --- a/.github/workflows/wheel-publish.yml +++ b/.github/workflows/wheel-publish.yml @@ -6,10 +6,63 @@ on: types: - published +permissions: + contents: read + +defaults: + run: + shell: bash + +concurrency: + group: pypi-publish-${{ github.event.release.id }} + cancel-in-progress: false jobs: + verify-ci: + name: Verify required CI workflows + runs-on: ubuntu-latest + timeout-minutes: 10 + if: github.event_name == 'release' && github.event.action == 'published' + permissions: + actions: read + contents: read + + steps: + - name: Checkout repository + uses: actions/checkout@v6.0.2 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Verify successful CI runs for release commit + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_TAG: ${{ github.event.release.tag_name }} + REPOSITORY: ${{ github.repository }} + run: | + set -euo pipefail + + release_sha="$(git rev-list -n 1 "refs/tags/${RELEASE_TAG}")" + echo "Checking CI status for ${RELEASE_TAG} at ${release_sha}" + + for workflow in ci-lint.yml ci-test.yml; do + conclusion="$( + gh api \ + "repos/${REPOSITORY}/actions/workflows/${workflow}/runs?head_sha=${release_sha}&status=completed&event=push&per_page=1" \ + --jq '.workflow_runs[0].conclusion // ""' + )" + + if [[ "${conclusion}" != "success" ]]; then + echo "Required workflow ${workflow} is not green for ${release_sha}." + echo "Latest completed push-run conclusion: ${conclusion:-}" + exit 1 + fi + done + build: name: Build distributions + needs: verify-ci + if: always() && (needs.verify-ci.result == 'success' || needs.verify-ci.result == 'skipped') runs-on: ubuntu-latest timeout-minutes: 15 @@ -47,14 +100,18 @@ jobs: name: release-dists path: dist/* if-no-files-found: error + retention-days: 7 upload_all: - needs: [build] + name: Publish distributions + needs: [verify-ci, build] environment: pypi permissions: id-token: write runs-on: ubuntu-latest + timeout-minutes: 10 if: github.event_name == 'release' && github.event.action == 'published' + steps: - name: Download distributions uses: actions/download-artifact@v8.0.0 @@ -66,4 +123,3 @@ jobs: uses: pypa/gh-action-pypi-publish@v1.13.0 with: packages-dir: dist/ - diff --git a/pyproject.toml b/pyproject.toml index 67145fe..ded1ac6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,47 +1,56 @@ +[build-system] +requires = ["setuptools>=80", "wheel"] +build-backend = "setuptools.build_meta" + [project] name = "dementor" version = "1.0.0.dev20" # REVISIT: dynamic version # dynamic = ["version"] -license-files = ["LICENSE"] - +description = "LLMNR/NBT-NS/mDNS Poisoner and rogue service provider" +readme = "docs/README.pypi.md" +license = "MIT" # Python 3.11 required as tomllib was added in 3.11 requires-python = ">=3.11" -description = "LLMNR/NBT-NS/mDNS Poisoner and rogue service provider" authors = [{ name = "MatrixEditor" }] maintainers = [{ name = "MatrixEditor" }] -readme = "docs/README.pypi.md" +keywords = [ + "llmnr", + "mdns", + "nbt-ns", + "network-security", + "penetration-testing", + "poisoner", + "rogue-services", +] classifiers = [ "Development Status :: 4 - Beta", + "Environment :: Console", "Intended Audience :: Developers", - "Intended Audience :: Science/Research", - "Programming Language :: Python :: 3", + "Intended Audience :: Information Technology", + "Operating System :: POSIX", + "Operating System :: Unix", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", - "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Security", "Topic :: System :: Networking", - "Typing :: Typed", - "Operating System :: POSIX", - "Operating System :: Unix", ] - dependencies = [ - "rich", + "aiosmtpd", + "aioquic", + "caterpillar-py>=2.8.1", "impacket", + "jinja2", + "pyasn1", + "pyipp", + "rich", "scapy", - "aiosmtpd", "sqlalchemy", - "pyasn1", - "aioquic", "typer", - "jinja2", "typing-extensions", - "caterpillar-py>=2.8.1", - "pyipp", ] [project.scripts] @@ -49,9 +58,10 @@ dementor = "dementor.standalone:run_from_cli" Dementor = "dementor.standalone:run_from_cli" [project.urls] -homepage = "https://matrixeditor.github.io/dementor" -documentation = "https://matrixeditor.github.io/dementor" -source = "https://github.com/MatrixEditor/dementor" +Homepage = "https://matrixeditor.github.io/dementor" +Documentation = "https://matrixeditor.github.io/dementor" +Source = "https://github.com/MatrixEditor/dementor" +Issues = "https://github.com/MatrixEditor/dementor/issues" [tool.setuptools.packages.find] where = ["."] @@ -60,22 +70,17 @@ include = ["dementor*"] [tool.setuptools.package-data] dementor = ["assets/**"] -[project.optional-dependencies] +[dependency-groups] +dev = [ + "pytest", + "ruff", +] docs = [ - "sphinx", "shibuya", + "sphinx", "sphinx-copybutton", "sphinx-design", ] -dev = [ - "pytest", - "ruff", - "ty", -] - -[build-system] -requires = ["setuptools>=80", "wheel", "setuptools-scm[simple]>=8"] -build-backend = "setuptools.build_meta" [tool.pytest.ini_options] testpaths = ["tests"] @@ -194,4 +199,4 @@ docstring-code-format = true # REVISIT: dynamic version # [tool.setuptools_scm] -# version_file = "dementor/version.py" \ No newline at end of file +# version_file = "dementor/version.py"