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
64 changes: 64 additions & 0 deletions .github/scripts/bump_formula.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env python3
"""Update the RegShape Homebrew formula to a given version.

Fetches the sdist URL and sha256 for ``regshape==<version>`` from PyPI and
rewrites the top-level ``url``/``sha256`` fields of the formula (the package
source, not the dependency ``resource`` blocks).

Usage:
python bump_formula.py <version>

The formula is always read from and written to a fixed, constant path relative to
the current working directory, so no caller-supplied data is ever used to build a
filesystem path. Run this script from the tap checkout root.
"""
from __future__ import annotations

import json
import re
import sys
import time
import urllib.request

# Constant path (relative to CWD); never derived from user input.
FORMULA_PATH = "Formula/regshape.rb"


def fetch_sdist(version: str) -> tuple[str, str]:
url = f"https://pypi.org/pypi/regshape/{version}/json"
last_err: Exception | None = None
for _ in range(30):
try:
with urllib.request.urlopen(url, timeout=30) as resp:
data = json.load(resp)
for entry in data["urls"]:
if entry["packagetype"] == "sdist":
return entry["url"], entry["digests"]["sha256"]
raise RuntimeError(f"No sdist found for regshape {version}")
except Exception as err: # noqa: BLE001 - retry on propagation delay
last_err = err
time.sleep(10)
raise RuntimeError(f"regshape {version} not available on PyPI: {last_err}")


def bump(version: str) -> None:
sdist_url, sha256 = fetch_sdist(version)
with open(FORMULA_PATH, encoding="utf-8") as fh:
text = fh.read()
# Only the top-level fields are indented with exactly two spaces; resource
# blocks use four spaces, so anchored two-space matches target the package.
text, n_url = re.subn(r'^ url ".*"$', f' url "{sdist_url}"', text, count=1, flags=re.M)
text, n_sha = re.subn(r'^ sha256 ".*"$', f' sha256 "{sha256}"', text, count=1, flags=re.M)
if n_url != 1 or n_sha != 1:
raise RuntimeError("Failed to locate top-level url/sha256 in formula")
with open(FORMULA_PATH, "w", encoding="utf-8") as fh:
fh.write(text)
print(f"Bumped {FORMULA_PATH} to regshape {version}")
print(f" url {sdist_url}")
print(f" sha256 {sha256}")


if __name__ == "__main__":
if len(sys.argv) != 2:
sys.exit("usage: bump_formula.py <version>")
bump(sys.argv[1])
59 changes: 58 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
name: Publish to PyPI
name: Publish to PyPI and bump Homebrew formula

on:
release:
types: [published]

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -51,3 +54,57 @@ jobs:
path: dist/

- uses: pypa/gh-action-pypi-publish@release/v1

homebrew:
needs: publish
runs-on: ubuntu-latest
steps:
- name: Checkout regshape
uses: actions/checkout@v4

- name: Checkout Homebrew tap
uses: actions/checkout@v4
with:
repository: toddysm/homebrew-regshape
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
path: tap

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Bump formula to released version
id: bump
working-directory: tap
run: |
VERSION="${GITHUB_REF_NAME#v}"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
python "${GITHUB_WORKSPACE}/.github/scripts/bump_formula.py" "$VERSION"

- name: Open pull request in tap
env:
GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
VERSION: ${{ steps.bump.outputs.version }}
run: |
cd tap
if git diff --quiet; then
echo "Formula already up to date; nothing to do."
exit 0
fi
BRANCH="bump-regshape-${VERSION}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git switch -C "$BRANCH"
git commit -am "regshape ${VERSION}"
git push -u origin "$BRANCH" --force-with-lease
if gh pr view "$BRANCH" --repo toddysm/homebrew-regshape --json state \
--jq '.state' 2>/dev/null | grep -qx OPEN; then
echo "An open PR already exists for ${BRANCH}; the force-push updated it."
exit 0
fi
gh pr create \
--repo toddysm/homebrew-regshape \
--base main \
--head "$BRANCH" \
--title "regshape ${VERSION}" \
--body "Automated formula bump for regshape ${VERSION}, triggered by the release workflow in toddysm/regshape."
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# RegShape

![GitHub issues](https://img.shields.io/github/issues-raw/toddysm/regshape?link=https%3A%2F%2Fgithub.com%2Ftoddysm%2Fregshape%2Fissues)
![GitHub pull requests](https://img.shields.io/github/issues-pr-raw/toddysm/regshape?link=https%3A%2F%2Fgithub.com%2Ftoddysm%2Fregshape%2Fpulls)
![GitHub pull requests](https://img.shields.io/github/issues-pr-raw/toddysm/regshape?link=https%3A%2F%2Fgithub.com%2Ftoddysm%2Fregshape%2Fpulls)

<p align="center">
<img src="./docs/media/regshape-logo.png" alt="RegShape" width="256">
Expand All @@ -26,9 +26,9 @@ an intention to break the consistency of the artifacts.
You can use RegShape in two modes:

- **Standard mode** — interact with registries as you would with any other tool:
pull and push manifests, blobs, tags, and more.
pull and push manifests, blobs, tags, and more.
- **Expert / break mode** — manually craft requests to test registry
implementations and probe their security boundaries.
implementations and probe their security boundaries.

RegShape is written in Python and offers Python libraries that can be leveraged
to build your own tools. The CLI is built on top of the libraries and uses the
Expand All @@ -39,6 +39,13 @@ to build your own tools. The CLI is built on top of the libraries and uses the
## Installation

```bash
# Homebrew (macOS / Linux) — recommended
brew install toddysm/regshape/regshape

# pip (from PyPI)
pip install regshape

# From source
git clone https://github.com/toddysm/regshape.git
cd regshape
pip install -e .
Expand Down
Empty file added docs/guides/homebrew-install.md
Empty file.
Loading