Skip to content

feat(ci): add PyPI release workflow for splunk-ao-a2a#56

Merged
adityamehra merged 3 commits into
mainfrom
feat/release-splunk-ao-a2a-pypi
Jun 29, 2026
Merged

feat(ci): add PyPI release workflow for splunk-ao-a2a#56
adityamehra merged 3 commits into
mainfrom
feat/release-splunk-ao-a2a-pypi

Conversation

@adityamehra

Copy link
Copy Markdown
Member

Summary

Adds .github/workflows/release-splunk-ao-a2a.yaml — a workflow_dispatch pipeline that builds and publishes the splunk-ao-a2a package to PyPI.

How it works

  1. Trigger manually from the Actions tab with a required version (e.g. 0.1.0)
  2. Patches splunk-ao-a2a/pyproject.toml and splunk-ao-a2a/src/splunk_ao_a2a/_version.py locally (no commit back)
  3. Builds with python -m build (hatchling backend)
  4. Publishes to PyPI via OIDC Trusted Publisher — no stored API token needed

Notes

  • All action references pinned to commit SHA (matching ci-tests-splunk-ao-a2a.yaml pattern)
  • Version input is required to prevent accidental releases
  • Matches the pending Trusted Publisher on pypi.org (workflow: release-splunk-ao-a2a.yaml, environment: pypi)

Made with Cursor

adityamehra and others added 2 commits June 29, 2026 13:06
Co-authored-by: Cursor <cursoragent@cursor.com>
Reject bump keywords (patch, major, etc.) and malformed inputs with a
clear error before any file is modified, matching the pattern added to
the splunk-ao and splunk-ao-adk release workflows

Co-authored-by: Cursor <cursoragent@cursor.com>
@adityamehra

Copy link
Copy Markdown
Member Author

Applied the same changesets from PR #48 to this workflow:

Version input validation — Added an upfront grep -Eq check that rejects anything that is not an explicit PEP 440 version number (e.g. 0.1.0, 1.2.3b1). Bump keywords like patch, major, or minor will now fail fast with a clear ::error:: message before touching any files. (SHA pinning was already in place from the initial commit.)

- Fix regex to correctly accept rc, .dev, and .post PEP 440 forms
- Add permissions: contents: read to the build job

Co-authored-by: Cursor <cursoragent@cursor.com>

@fercor-cisco fercor-cisco left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🤖 This review was generated by the Astra agent (claude-opus-4-8). It may contain mistakes.

Verdict: approve — Workflow is correct and well-structured (SHA-pinned, least-privilege, OIDC publish); only hardening/design improvements remain, none blocking.

General Comments

  • 🟡 minor (design): This release path manually rewrites the version in pyproject.toml/_version.py at build time and does not commit or tag the result back to git ("no commit back" per the PR description). Meanwhile splunk-ao-a2a/pyproject.toml carries a full [tool.semantic_release] config (tag_format = "splunk-ao-a2a-v{version}", version_variables/version_toml) that implies releases are meant to be tagged. The result is that a published PyPI version has no corresponding git tag/commit, so there's no traceability from a release artifact back to source. Worth clarifying the intended release model: is semantic-release being abandoned for this package, or should this workflow also create a tag/release? Not blocking, but the two mechanisms are inconsistent.

Follow-ups

Suggested follow-up work that could be tracked as Shortcut stories:

  • .github/workflows/release-splunk-ao-a2a.yaml:17-17: Consider adding a concurrency group to the workflow (the CI workflow already has one) so two manual dispatches can't race to build/publish the same package simultaneously.
  • .github/workflows/release-splunk-ao-a2a.yaml:81-85: There is no guard against re-publishing an already-released version; PyPI will reject a duplicate and the run will fail late. Optionally add an early check (e.g. query the PyPI JSON API for the target version) to fail fast with a clear message before building.

Comment on lines +34 to +45
if ! printf '%s' "$INPUT_VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+((a|b|rc)[0-9]+)?(\.post[0-9]+)?(\.dev[0-9]+)?$'; then
echo "::error::Invalid version '${INPUT_VERSION}'. Expected an explicit version like 0.1.0, 1.2.3rc1, or 1.2.3.post1. Bump keywords like 'patch' or 'major' are not accepted."
exit 1
fi
sed -i "s/^version = \".*\"/version = \"${INPUT_VERSION}\"/" pyproject.toml
sed -i "s/__version__ = \".*\"/__version__ = \"${INPUT_VERSION}\"/" src/splunk_ao_a2a/_version.py

- name: Get current version
id: get-version
run: |
VERSION=$(grep '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/')
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟠 major (security): The version validation can be bypassed by a multi-line input, which then flows unsanitized into the sed replacement string. grep -Eq '^...$' matches on a per-line basis, so an input such as 0.1.0\n<arbitrary> passes the check (line 1 matches) even though the whole value is not a valid version. The raw $INPUT_VERSION is then interpolated into sed -i "s/^version = \".*\"/version = \"${INPUT_VERSION}\"/"; an embedded newline terminates the s command and the remainder is parsed as additional sed commands (e.g. e/w), giving command/file-write execution in CI. workflow_dispatch string inputs are single-line in the UI but can contain newlines when dispatched via the REST API / gh workflow run. Although dispatching requires write access, code execution inside a release pipeline is worth closing off. Prefer bash's [[ =~ ]], whose ^/$ anchor the entire string and where . does not cross newlines, so multi-line input is rejected. The same hardening should be mirrored in any sibling release workflow.

Suggested change
if ! printf '%s' "$INPUT_VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+((a|b|rc)[0-9]+)?(\.post[0-9]+)?(\.dev[0-9]+)?$'; then
echo "::error::Invalid version '${INPUT_VERSION}'. Expected an explicit version like 0.1.0, 1.2.3rc1, or 1.2.3.post1. Bump keywords like 'patch' or 'major' are not accepted."
exit 1
fi
sed -i "s/^version = \".*\"/version = \"${INPUT_VERSION}\"/" pyproject.toml
sed -i "s/__version__ = \".*\"/__version__ = \"${INPUT_VERSION}\"/" src/splunk_ao_a2a/_version.py
- name: Get current version
id: get-version
run: |
VERSION=$(grep '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/')
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
- name: Set version
env:
INPUT_VERSION: ${{ inputs.version }}
run: |
if [[ ! "$INPUT_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+((a|b|rc)[0-9]+)?(\.post[0-9]+)?(\.dev[0-9]+)?$ ]]; then
echo "::error::Invalid version '${INPUT_VERSION}'. Expected an explicit version like 0.1.0, 1.2.3rc1, or 1.2.3.post1. Bump keywords like 'patch' or 'major' are not accepted."
exit 1
fi
sed -i "s/^version = \".*\"/version = \"${INPUT_VERSION}\"/" pyproject.toml
sed -i "s/__version__ = \".*\"/__version__ = \"${INPUT_VERSION}\"/" src/splunk_ao_a2a/_version.py

🤖 Generated by Astra

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good catch — switched from grep -Eq to bash [[ =~ ]] across all three PyPI release workflows. The [[ =~ ]] operator anchors ^/$ to the entire string rather than matching per-line, so a multi-line input like 0.1.0\n<payload> is now rejected outright. Fixed in PR #59.

@adityamehra adityamehra merged commit b0ffaef into main Jun 29, 2026
13 checks passed
@adityamehra adityamehra deleted the feat/release-splunk-ao-a2a-pypi branch June 29, 2026 23:05
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 29, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants