From c1880e5d923402be7db58b5b9b54cc6b1a1cb37b Mon Sep 17 00:00:00 2001 From: JulioLoayzaM Date: Thu, 30 May 2024 17:23:43 +0200 Subject: [PATCH] add workflow Increased the timeout for the TestU01 installation, and only capture output if not in the workflow. Uses the pypa action with trusted publishing for publishing the package (on TestPyPI for now). --- .github/workflows/main.yml | 213 ++++++++++++++++++++++++++++ Makefile | 104 ++++++++------ crypto_condor/primitives/TestU01.py | 25 +--- docs/Makefile | 2 +- pyproject.toml | 2 +- 5 files changed, 285 insertions(+), 61 deletions(-) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..c3e9c0a --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,213 @@ +name: main + +on: [push] + +jobs: + setup: + runs-on: ubuntu-22.04 + steps: + - name: Checkout repo + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: "pip" + - name: Install dependencies + run: make ci-setup + - name: Cache venv + id: cache-venv + uses: actions/cache@v4 + with: + path: .venv + key: ${{ runner.os }}-venv + + lint: + runs-on: ubuntu-22.04 + needs: [setup] + steps: + - name: Checkout repo + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: "pip" + - name: Restore venv + id: cache-venv-restore + uses: actions/cache/restore@v4 + with: + path: .venv + key: ${{ runner.os }}-venv + - name: Run the linter + run: | + source .venv/bin/activate + make lint-ci + + type-check: + runs-on: ubuntu-22.04 + needs: [setup] + steps: + - name: Checkout repo + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: "pip" + - name: Restore venv + id: cache-venv-restore + uses: actions/cache/restore@v4 + with: + path: .venv + key: ${{ runner.os }}-venv + - name: Run the type-checker + run: | + source .venv/bin/activate + make type-check-ci + + test: + runs-on: ubuntu-22.04 + needs: [lint,type-check] + steps: + - name: Checkout repo + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: "pip" + - name: Restore venv + id: cache-venv-restore + uses: actions/cache/restore@v4 + with: + path: .venv + key: ${{ runner.os }}-venv + - name: Run the test suite and coverage + run: | + source .venv/bin/activate + make coverage-ci + make doctest-ci + + docs: + runs-on: ubuntu-22.04 + needs: [lint,type-check] + steps: + - name: Checkout repo + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: "pip" + - name: Restore venv + id: cache-venv-restore + uses: actions/cache/restore@v4 + with: + path: .venv + key: ${{ runner.os }}-venv + - name: Build the docs + run: | + source .venv/bin/activate + make docs-ci + + upload-docs: + if: success() && github.ref == 'refs/heads/main' + needs: [test,docs] + runs-on: ubuntu-22.04 + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: "pip" + - name: Restore venv + id: cache-venv-restore + uses: actions/cache/restore@v4 + with: + path: .venv + key: ${{ runner.os }}-venv + - name: Build docs for publishing + run: | + source .venv/bin/activate + make pages-ci + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: docs/build/public + + pages: + needs: [upload-docs] + if: success() && github.ref == 'refs/heads/main' + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-22.04 + steps: + - name: Publish to pages + id: deployment + uses: actions/deploy-pages@v4 + + build: + needs: [test,docs] + if: success() && github.ref == 'refs/heads/main' + runs-on: ubuntu-22.04 + steps: + - name: Checkout repo + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: "pip" + - name: Restore venv + id: cache-venv-restore + uses: actions/cache/restore@v4 + with: + path: .venv + key: ${{ runner.os }}-venv + - name: Build the package + run: | + source .venv/bin/activate + make build-ci + - name: Upload build + uses: actions/upload-artifact@v3 + with: + name: package-build + path: ./dist/* + + publish: + needs: [build] + if: success() && startsWith(github.ref, 'refs/tags') + runs-on: ubuntu-22.04 + environment: + name: testpypi + url: https://test.pypi.org/p/crypto-condor + permissions: + contents: write + id-token: write + steps: + - name: Checkout repo + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: "pip" + - name: Download build + uses: actions/download-artifact@v3 + with: + # By omitting the name we are downloading all the artifacts + path: ./dist/ + - name: Publish the package + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: https://test.pypi.org/legacy/ + diff --git a/Makefile b/Makefile index 991be62..ff34450 100644 --- a/Makefile +++ b/Makefile @@ -19,24 +19,6 @@ help: # Show help for each of the Makefile recipes. all: lint coverage docs doctest -lint: # Format with black and lint with ruff. - @echo "[+] Linting" - black --check . - ruff check . - -lint-ci: # Format with black, lint with ruff, generate report for CI. - @echo "[+] Linting (CI)" - black --check . - ruff check --output-format=gitlab . | tee code-quality-report.json - -type-check: # Run mypy. - @echo "[+] Type checking" - mypy --config-file pyproject.toml . - -type-check-ci: # Run mypy, generate report for CI. - @echo "[+] Type checking (CI)" - mypy --config-file pyproject.toml --junit-xml mypy.xml . - .PHONY: import-nist-vectors import-nist-vectors: # Serialize NIST test vectors with protobuf. import-nist-vectors: $(PROTO_FILES:%.proto=%.imported) @@ -50,6 +32,12 @@ compile-primitives: # Compile primitives written in C. cd crypto_condor/primitives && $(MAKE) all -j4 @echo +compile-primitives-ci: # Compile primitives written in C. + @echo "[+] Compiling primitives (CI)" + sudo apt-get install -y --no-install-recommends pandoc texlive texlive-latex-extra + cd crypto_condor/primitives && $(MAKE) all -j4 + @echo + copy-guides: # Copy guides from the docs for the method command. @echo "[+] Copying guides from the documentation" python utils/copy_guides.py @@ -66,13 +54,52 @@ install: # Install using poetry. poetry install --with=dev,docs @echo +ci-setup: # Basic commands to run before the other CI targets. +ci-setup: + @echo "[+] Setup CI" + export PYTHONDONTWRITEBYTECODE=1 + export POETRY_VIRTUALENVS_IN_PROJECT=1 + python --version + python -m pip --version + python -m pip install poetry + poetry --version + poetry install --with=dev,docs + init: # Common requirements for several targets. init: install import-nist-vectors compile-primitives copy-guides copy-contributing +init-ci: # Common requirements before other CI targets. +init-ci: ci-setup import-nist-vectors copy-guides copy-contributing + +lint: # Format with black and lint with ruff. + @echo "[+] Linting" + black --check . + ruff check . + +lint-ci: # Format with black, lint with ruff, generate report for CI. +lint-ci: init-ci + @echo "[+] Linting (CI)" + poetry run black --check . + poetry run ruff check --output-format=github . + +type-check: # Run mypy. + @echo "[+] Type checking" + mypy --config-file pyproject.toml . + +type-check-ci: # Run mypy, generate report for CI. +type-check-ci: init-ci + @echo "[+] Type checking (CI)" + poetry run mypy --config-file pyproject.toml --junit-xml mypy.xml . + doctest: # Run doctest -doctest: install +doctest: init $(MAKE) -C docs doctest +doctest-ci: # Run doctest +doctest-ci: init-ci + sudo apt-get install -y --no-install-recommends pandoc + . .venv/bin/activate && $(MAKE) -C docs doctest + test: # Run pytest. test: init @echo "[+] Testing" @@ -81,14 +108,14 @@ test: init coverage: # Run coverage, generate HTML report. coverage: init @echo "[+] Testing and checking coverage" - pytest --cov="crypto_condor" --cov-report html -n auto tests/ + pytest --cov="crypto_condor" --cov-report html --numprocesses=auto tests/ coverage-ci: # Run coverage, generate JUnit test report and XML coverage report. -coverage-ci: init +coverage-ci: init-ci compile-primitives-ci @echo "[+] Testing and checking coverage (CI)" - pytest -v --junitxml=report.xml --cov="crypto_condor" --cov-report xml -n auto tests/ + poetry run pytest --verbose --junitxml=junit/test-results.xml --cov="crypto_condor" --cov-report=xml --numprocesses=auto tests/ # Print coverage report so that CI picks up stats - coverage report + poetry run coverage report # Separate build target to fully build locally. build: # Build the package. @@ -99,19 +126,18 @@ build: init # This is redundant since publish-ci also builds the package, but we use this to check # for building errors before trying to publish. build-ci: # Build the package in the CI. -build-ci: init +build-ci: init-ci compile-primitives-ci @echo "[+] Building package (CI)" # Ensure that the tag and version match to avoid pushing a package without # the corresponding documentation. - python utils/check_tag_and_version.py + . .venv/bin/activate && python utils/check_tag_and_version.py poetry build publish-ci: # Publish package using the CI pipeline. publish-ci: init @echo "[+] Publishing package (CI)" - poetry config repositories.gitlab $(CI_API_V4_URL)/projects/$(CI_PROJECT_ID)/packages/pypi -# JOB_TOKEN is an ephemeral token that is valid while the pipeline is running. - @poetry publish -v --build --repository gitlab --cert $(CI_SERVER_TLS_CA_FILE) -u gitlab-ci-token -p $(CI_JOB_TOKEN) + @poetry config pypi-token.pypi $(PYPI_TOKEN) + @poetry publish -v --build compile-proto: # Compile .proto files and prints current protoc version. compile-proto: $(PB2_FILES) @@ -124,26 +150,24 @@ compile-proto: $(PB2_FILES) # This should only be called on main since the published docs are based on that # branch. pages-ci: # Build the documentation for GitLab Pages. -pages-ci: install +pages-ci: init-ci @echo "[+] Building all docs" - $(MAKE) -C docs all-versions - mv docs/build/public . -# Move the current docs to devel - mv public/main public/devel + sudo apt-get install -y --no-install-recommends pandoc + . .venv/bin/activate && $(MAKE) -C docs all-versions + mv docs/build/public/main docs/build/public/devel # Move latest tag to latest. -# This step might fail if the version is bumped since the CI runs once for the -# commit and once more for the tag, so the latest tag might not be present in -# the first run. We ignore the error and copy what would be the staging docs to -# stable. Since this should only occur when pushing a tag, the staging docs -# *are* the stable docs and the CI pipeline for the tag will overwrite these -# anyway. - -LATEST_TAG="$(shell git describe --tags --abbrev=0 --exclude='*rc[0-9]')"; cp -R public/$$LATEST_TAG public/latest + -LATEST_TAG="$(shell git describe --tags --abbrev=0 --exclude='*rc[0-9]')" && cp -R docs/build/public/$$LATEST_TAG docs/build/public/latest .PHONY: docs docs: # Build the documentation docs: install $(MAKE) -C docs html +docs-ci: # Build the documentation +docs-ci: init-ci + sudo apt-get install -y --no-install-recommends pandoc + . .venv/bin/activate && $(MAKE) -C docs html + livedocs: # Build the documentation with live reload. livedocs: install $(MAKE) -C docs livehtml diff --git a/crypto_condor/primitives/TestU01.py b/crypto_condor/primitives/TestU01.py index 279ad08..e7ac513 100644 --- a/crypto_condor/primitives/TestU01.py +++ b/crypto_condor/primitives/TestU01.py @@ -91,34 +91,21 @@ def install_testu01(): with Progress() as progress: task = progress.add_task("Compiling TestU01, please wait", total=None) + # Only capture output if it's not running in the CI, otherwise we want to see + # what's going on in case of an error. + capture_output = not os.environ.get("GITHUB_ACTIONS", False) try: - result = subprocess.run( + _ = subprocess.run( [str(make)], cwd=t_dir, - capture_output=True, + capture_output=capture_output, text=True, check=True, - timeout=60, + timeout=300, ) progress.update(task, completed=True) except (subprocess.CalledProcessError, subprocess.TimeoutExpired): logger.exception("Could not compile TestU01") - # The compilation log is very long so we save it to a file to make it - # easier to read/share. In CI, print it so we get it in the captured output. - if os.environ.get("GITLAB_CI", False): # pragma: no cover (CI) - print("STDOUT:", result.stdout) - print("STDERR:", result.stderr) - else: - try: - with open("testu01.log", "w") as tlog: - tlog.write("STDOUT:") - tlog.write(result.stdout) - tlog.write("\n\n\nSTDERR:") - tlog.write(result.stderr) - logger.info("Saved compilation log to testu01.log") - except OSError: - logger.exception("Could not save compilation log to testu01.log") - logger.info("Dumping log to stdout") raise diff --git a/docs/Makefile b/docs/Makefile index befad0b..34e5aa8 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -14,7 +14,7 @@ help: .PHONY: help Makefile -VERSIONS = main 2024.02.05 2024.01.08 +VERSIONS = main all-versions: $(VERSIONS) git checkout main diff --git a/pyproject.toml b/pyproject.toml index aa2ea1e..c11c283 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "crypto-condor" -version = "2024.02.05" +version = "2024.05.30-rc1" description = "Compliance testing for implementations of cryptographic primitives" license = "Apache-2.0" authors = [