Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: release

# Publish to PyPI when a GitHub Release is published (the GitHub release flow).
# Uses PyPI Trusted Publishing (OIDC) — no API token is stored in the repo.
# One-time PyPI setup: add a trusted publisher for project `optimum-keysync`
# with this repo, workflow file `release.yml`, and environment `pypi`.
on:
release:
types: [published]

permissions:
contents: read

concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false

jobs:
pypi:
runs-on: ubuntu-latest
timeout-minutes: 10
environment:
name: pypi
url: https://pypi.org/project/optimum-keysync/
permissions:
contents: read
id-token: write # OIDC token for Trusted Publishing; no stored secret
steps:
# Action versions pinned to commit SHAs (tag in the comment) per the
# OpenSSF / GitHub-hardening guidance used across this repo's workflows.
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Disable checkout credential persistence.

This job never pushes to GitHub, so keeping the checkout token in local git config only increases exposure to later steps and build hooks.

Suggested fix
-      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+        with:
+          persist-credentials: false

As per path instructions, "Check permissions (least privilege) ... Flag secret exposure in logs, overly broad permissions" and zizmor warns "credential persistence through GitHub Actions artifacts (artipacked)."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
🧰 Tools
🪛 zizmor (1.26.1)

[warning] 31-31: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml at line 31, The checkout step in the release
workflow is persisting credentials unnecessarily, so update the actions/checkout
usage to disable credential persistence for this job. Adjust the checkout
configuration so the workflow still fetches the repo but does not keep the token
in local git config, and keep the change scoped to the checkout action
invocation in the release job.

Sources: Path instructions, Linters/SAST tools


- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
with:
python-version: "3.12"

# Guard against tag/version drift: the package version (single source,
# src/optimum_keysync/__init__.py) must match the release tag (with an
# optional leading `v`), so a release never publishes a different version
# than it claims.
- name: verify tag matches package version
run: |
pkg=$(PYTHONPATH=src python -c "import optimum_keysync; print(optimum_keysync.__version__)")
tag="${GITHUB_REF_NAME#v}"
if [ "$pkg" != "$tag" ]; then
echo "::error::release tag ${GITHUB_REF_NAME} (-> ${tag}) does not match pyproject version ${pkg}"
exit 1
fi

- name: build sdist + wheel
run: |
python -m pip install --upgrade build
python -m build

- name: publish to PyPI
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,16 @@ pytest

Tests are hermetic: `respx` stubs every outbound HTTP call, so no live API or
beacon access is required.

## Releasing

Publishing to PyPI is automated via `.github/workflows/release.yml`, which runs
when a GitHub Release is published and uploads with PyPI Trusted Publishing
(OIDC) — no token is stored in the repo. To cut a release:

1. Bump `version` in `pyproject.toml` and merge to `main`.
2. Publish a GitHub Release tagged `v<version>` (e.g. `v1.0.0`).
Comment on lines +140 to +141

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Point the release docs at the real version source.

Line 140 still tells maintainers to bump pyproject.toml, but this PR’s workflow reads optimum_keysync.__version__. Following the README as written will cause the next tagged release to fail the version check. Also at: .github/workflows/release.yml: Line 46.

Suggested fix
-1. Bump `version` in `pyproject.toml` and merge to `main`.
+1. Bump `src/optimum_keysync/__init__.py`'s `__version__` and merge to `main`.

As per path instructions, "Prioritize technical accuracy and copy-pastable commands" and "Flag references to removed APIs, wrong paths, or steps that contradict the repo."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
1. Bump `version` in `pyproject.toml` and merge to `main`.
2. Publish a GitHub Release tagged `v<version>` (e.g. `v1.0.0`).
1. Bump `src/optimum_keysync/__init__.py`'s `__version__` and merge to `main`.
2. Publish a GitHub Release tagged `v<version>` (e.g. `v1.0.0`).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 140 - 141, The release instructions in the README are
pointing to the wrong version source, since the workflow uses
optimum_keysync.__version__ rather than pyproject.toml. Update the release docs
to tell maintainers to bump the version where the package actually reads it,
then commit, merge to main, and create the GitHub Release tagged v<version>;
also align the release workflow reference in .github/workflows/release.yml with
the same version source so the documented steps match the version check.

Source: Path instructions


The workflow verifies the tag matches the package version, builds the sdist and
wheel, and publishes. One-time setup: register the trusted publisher on PyPI
(project `optimum-keysync`, workflow `release.yml`, environment `pypi`).
2 changes: 1 addition & 1 deletion examples/kubernetes/cronjob.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ spec:
restartPolicy: Never
containers:
- name: keysync
image: ghcr.io/getoptimum/optimum-keysync:0.1.0
image: ghcr.io/getoptimum/optimum-keysync:1.0.0
args: ["sync", "--apply", "--log-format", "json"]
envFrom:
- configMapRef:
Expand Down
8 changes: 6 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ build-backend = "setuptools.build_meta"

[project]
name = "optimum-keysync"
version = "0.1.0"
# Single source of truth: src/optimum_keysync/__init__.py:__version__
dynamic = ["version"]
description = "Reconcile customer-owned Ethereum validator indices against Optimum's validator registry (console API). Cron-friendly CLI that authenticates with an ovi_live_* operator API key, diffs the desired set against the registry, and applies the delta."
readme = "README.md"
requires-python = ">=3.11"
license = { text = "MIT" }
authors = [{ name = "Optimum" }]
keywords = ["ethereum", "validator", "optimum", "keysync", "sync", "operator"]
classifiers = [
"Development Status :: 3 - Alpha",
"Development Status :: 5 - Production/Stable",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
Expand Down Expand Up @@ -42,6 +43,9 @@ keysync = "optimum_keysync.cli:main"
Homepage = "https://github.com/getoptimum/optimum-customer-key-import"
Issues = "https://github.com/getoptimum/optimum-customer-key-import/issues"

[tool.setuptools.dynamic]
version = { attr = "optimum_keysync.__version__" }

[tool.setuptools.packages.find]
where = ["src"]

Expand Down
2 changes: 1 addition & 1 deletion src/optimum_keysync/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""optimum-keysync: reconcile operator validator assignments against the Optimum console API."""

__version__ = "0.1.0"
__version__ = "1.0.0"

__all__ = ["__version__"]
Loading