Skip to content
Open
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
5 changes: 5 additions & 0 deletions .github/actionlint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
paths:
.github/workflows/**/*.yml:
ignore:
- 'property "workflow_(repository|sha)" is not defined'
- 'reusable workflow call "\$/'
20 changes: 13 additions & 7 deletions .github/workflows/cla-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@ name: "CLA Assistant (Reusable)"
on:
workflow_call:

permissions: {}

jobs:
CLAAssistant:
permissions:
pull-requests: write
statuses: write
contents: read
runs-on: ubuntu-24.04
steps:
- name: Generate token from GitHub App
id: app-token
uses: actions/create-github-app-token@v3
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
Expand All @@ -31,7 +37,7 @@ jobs:

for LOGIN in $COMMITTERS; do
if [ -z "$LOGIN" ] || [ "$LOGIN" = "null" ]; then
echo "Unknown committer (no GitHub login) — not exempt"
echo "Unknown committer (no GitHub login): not exempt"
ALL_EXEMPT=false
continue
fi
Expand All @@ -40,21 +46,21 @@ jobs:

AUTHOR_TYPE=$(gh api "users/${LOGIN}" --jq '.type' 2>/dev/null || echo "Unknown")
if [ "$AUTHOR_TYPE" = "Bot" ]; then
echo "$LOGIN is a Bot account — exempt"
echo "$LOGIN is a Bot account: exempt"
EXEMPT=true
fi

if [ "$EXEMPT" = "false" ]; then
if gh api "orgs/blacklanternsecurity/members/$LOGIN" > /dev/null 2>&1; then
echo "$LOGIN is an org member — exempt"
echo "$LOGIN is an org member: exempt"
EXEMPT=true
fi
fi

if [ "$EXEMPT" = "true" ]; then
EXEMPT_LOGINS="${EXEMPT_LOGINS:+$EXEMPT_LOGINS,}$LOGIN"
else
echo "$LOGIN is not exempt — CLA required"
echo "$LOGIN is not exempt: CLA required"
ALL_EXEMPT=false
fi
done
Expand All @@ -74,13 +80,13 @@ jobs:
gh api --method POST "repos/${{ github.repository }}/statuses/${{ github.event.pull_request.head.sha }}" \
-f state=success \
-f context="CLAAssistant" \
-f description="CLA check skipped — all committers are org members or bots"
-f description="CLA check skipped: all committers are org members or bots"

- name: "CLA Assistant"
if: |
(steps.cla-check.outputs.all_exempt != 'true') &&
((github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target')
uses: contributor-assistant/github-action@v2.6.1
uses: contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08 # v2.6.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PERSONAL_ACCESS_TOKEN: ${{ steps.app-token.outputs.token }}
Expand Down
40 changes: 40 additions & 0 deletions .github/workflows/crates.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: crates.io
on:
workflow_call:
inputs:
working-directory:
type: string
default: .
setup-script:
description: Repository script run before cargo publish. It may append to $GITHUB_ENV.
type: string
default: ""
environment:
type: string
default: release
secrets:
CARGO_REGISTRY_TOKEN:
required: true

permissions:
contents: read

jobs:
crates:
runs-on: ubuntu-24.04
environment: ${{ inputs.environment }}
defaults:
run:
working-directory: ${{ inputs.working-directory }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- run: rustup show active-toolchain || rustup toolchain install
- if: inputs.setup-script != ''
env:
SCRIPT: ${{ inputs.setup-script }}
run: '"./$SCRIPT"'
- env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: cargo publish --locked
40 changes: 40 additions & 0 deletions .github/workflows/dependabot-auto-merge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Dependabot auto-merge
on:
workflow_call:

permissions: {}

jobs:
auto-merge:
if: github.event.pull_request.user.login == 'dependabot[bot]' && !github.event.repository.fork
runs-on: ubuntu-24.04
timeout-minutes: 180
permissions:
contents: write
pull-requests: write
checks: read
steps:
- id: metadata
uses: dependabot/fetch-metadata@25dd0e34f4fe68f24cc83900b1fe3fe149efef98 # v3.1.0
# dev carries no required checks (#139), so the green gate is here rather than in --auto.
- if: steps.metadata.outputs.update-type != 'version-update:semver-major'
env:
PR_URL: ${{ github.event.pull_request.html_url }}
HEAD: ${{ github.event.pull_request.head.sha }}
SELF: ${{ github.workflow }}
GH_TOKEN: ${{ github.token }}
run: |
others='[.[] | select(.workflow != env.SELF)]'
while :; do
sleep 30
checks=$(gh pr checks "$PR_URL" --json name,bucket,workflow --jq "$others") || true
[ "$(jq length <<<"$checks")" -gt 0 ] || continue
jq -e 'any(.bucket == "pending")' <<<"$checks" >/dev/null && continue
break
done
jq -r '.[] | "\(.bucket)\t\(.name)"' <<<"$checks"
if jq -e 'any(.bucket == "fail" or .bucket == "cancel")' <<<"$checks" >/dev/null; then
echo "::error::checks failed, not merging"
exit 1
fi
gh pr merge "$PR_URL" --squash --match-head-commit "$HEAD"
110 changes: 110 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
name: Docker
on:
workflow_call:
inputs:
image:
description: Registry repository, such as blacklanternsecurity/bbot
type: string
required: true
version:
description: version output of release-check.yml
type: string
required: true
prerelease:
type: string
required: true
major:
type: string
required: true
minor:
type: string
required: true
description:
description: Push README.md to the Docker Hub repository description
type: boolean
default: false
outputs:
images:
description: JSON list of pushed version references, for publish.yml images
value: ${{ jobs.plan.outputs.images }}

permissions:
contents: read

jobs:
plan:
runs-on: ubuntu-24.04
outputs:
builds: ${{ steps.read.outputs.builds }}
images: ${{ steps.read.outputs.images }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: ${{ job.workflow_repository }}
ref: ${{ job.workflow_sha }}
path: .shared
persist-credentials: false
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
- id: read
env:
IMAGE: ${{ inputs.image }}
VERSION: ${{ inputs.version }}
run: uv run --no-project --with packaging --with pyyaml python .shared/scripts/manifest.py images "$IMAGE" "$VERSION"

build:
needs: plan
runs-on: ubuntu-24.04
strategy:
matrix:
build: ${{ fromJSON(needs.plan.outputs.builds) }}
env:
RELEASE: ${{ inputs.prerelease == 'false' }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
- id: meta
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
images: ${{ inputs.image }}
flavor: |
latest=false
suffix=${{ matrix.build.suffix }}
tags: |
type=raw,value=${{ inputs.version }}
type=raw,value=dev,enable=${{ env.RELEASE == 'false' }}
type=raw,value=latest,enable=${{ env.RELEASE }}
type=raw,value=stable,enable=${{ env.RELEASE }}
type=raw,value=${{ inputs.major }}.${{ inputs.minor }},enable=${{ env.RELEASE }}
type=raw,value=${{ inputs.major }},enable=${{ env.RELEASE }}
- uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
context: .
file: ${{ matrix.build.file }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ matrix.build.file }}
cache-to: type=gha,mode=max,scope=${{ matrix.build.file }}

description:
if: inputs.description
needs: build
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: peter-evans/dockerhub-description@1b9a80c056b620d92cedb9d9b5a223409c68ddfa # v5.0.0
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
repository: ${{ inputs.image }}
115 changes: 115 additions & 0 deletions .github/workflows/maturin-wheels.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
name: Maturin wheels
on:
workflow_call:
inputs:
targets:
description: JSON object of maturin targets per platform family in FAMILIES. Override to drop targets a crate cannot build.
type: string
default: '{"linux": ["x86_64", "x86", "aarch64", "armv7", "s390x", "ppc64le"], "musllinux": ["x86_64", "x86", "aarch64", "armv7"], "windows": ["x64", "x86"], "macos": ["x86_64", "aarch64"]}'
manylinux:
description: manylinux policy for the linux family
type: string
default: "2_28"
before-script-linux:
description: Repository script sourced inside the linux and musllinux build containers. Its exports reach maturin.
type: string
default: ""
env:
description: JSON object of plain environment variables for every build
type: string
default: "{}"
outputs:
artifacts:
description: Artifact name pattern covering every wheel and the sdist
value: wheels-*

permissions:
contents: read

jobs:
python:
uses: $/.github/workflows/python-versions.yml

plan:
runs-on: ubuntu-24.04
outputs:
builds: ${{ steps.plan.outputs.builds }}
steps:
- id: plan
env:
TARGETS: ${{ inputs.targets }}
MANYLINUX: ${{ inputs.manylinux }}
FAMILIES: |
{
"linux": {"runner": {"*": "ubuntu-24.04"}, "container": true},
"musllinux": {"runner": {"*": "ubuntu-24.04"}, "manylinux": "musllinux_1_2", "container": true},
"windows": {"runner": {"*": "windows-2025"}, "manylinux": "", "container": false, "architecture": true},
"macos": {"runner": {"x86_64": "macos-15-intel", "aarch64": "macos-15"}, "manylinux": "", "container": false}
}
run: |
builds=$(jq -c --argjson families "$FAMILIES" --arg manylinux "$MANYLINUX" '
[to_entries[] | .key as $family | ($families[$family] // error("unknown family \($family)")) as $f | .value[] | {
family: $family,
target: .,
runner: ($f.runner[.] // $f.runner["*"] // error("no runner for \($family) \(.)")),
manylinux: ($f.manylinux // $manylinux),
container: $f.container,
architecture: (if $f.architecture then . else "" end)
}]' <<<"$TARGETS")
echo "builds=$builds" >> "$GITHUB_OUTPUT"

wheel:
needs: [python, plan]
runs-on: ${{ matrix.build.runner }}
strategy:
matrix:
build: ${{ fromJSON(needs.plan.outputs.builds) }}
env: ${{ fromJSON(inputs.env) }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- id: args
shell: bash
env:
VERSIONS: ${{ needs.python.outputs.versions }}
BEFORE: ${{ inputs.before-script-linux }}
run: |
{
echo "interpreters=$(jq -r 'map("-i python" + .) | join(" ")' <<<"$VERSIONS")"
echo "setup<<EOF"
jq -r '.[]' <<<"$VERSIONS"
echo "EOF"
echo "before=${BEFORE:+source ./$BEFORE}"
} >> "$GITHUB_OUTPUT"
- if: ${{ !matrix.build.container }}
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: ${{ steps.args.outputs.setup }}
architecture: ${{ matrix.build.architecture }}
- uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0
with:
target: ${{ matrix.build.target }}
args: --release --locked --out dist ${{ steps.args.outputs.interpreters }}
sccache: false
manylinux: ${{ matrix.build.manylinux }}
before-script-linux: ${{ steps.args.outputs.before }}
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: wheels-${{ matrix.build.family }}-${{ matrix.build.target }}
path: dist

sdist:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0
with:
command: sdist
args: --out dist
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: wheels-sdist
path: dist
Loading