Skip to content
Open
Show file tree
Hide file tree
Changes from 9 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
7 changes: 6 additions & 1 deletion .github/workflows/audit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@ on:
- cron: '0 12 * * 1' # Weekly on Mondays at noon UTC
workflow_dispatch:

permissions:
contents: read

jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- name: Set up Homebrew
uses: Homebrew/actions/setup-homebrew@b2a302b9a642580cae998e6ba2076ffd28e61317 # v5
Expand Down
241 changes: 241 additions & 0 deletions .github/workflows/bottles.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
name: Build Valhalla bottle

on:
workflow_dispatch:
inputs:
formula:
description: Versioned formula to build
required: true
type: choice
options:
- openjdk-valhalla@27
- openjdk-valhalla@28

permissions: {}

concurrency:
group: bottle-${{ inputs.formula }}
cancel-in-progress: false

jobs:
build:
runs-on: macos-14
permissions:
contents: read
env:
FORMULA: ${{ inputs.formula }}
TAP: artagon/jdkvalhalla
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- name: Set up Homebrew
uses: Homebrew/actions/setup-homebrew@b2a302b9a642580cae998e6ba2076ffd28e61317 # v5

- name: Verify Apple Silicon runner
run: |
set -Eeuo pipefail
[[ "$(uname -m)" == "arm64" ]] || {
printf 'Expected an arm64 runner, got %s\n' "$(uname -m)" >&2
exit 1
}

- name: Tap this checkout
run: |
set -Eeuo pipefail
brew untap "${TAP}" >/dev/null 2>&1 || true
brew tap --custom-remote "${TAP}" "${GITHUB_WORKSPACE}"

- name: Resolve bottle metadata
id: metadata
run: |
set -Eeuo pipefail
[[ "${GITHUB_REF}" == "refs/heads/main" ]] || {
printf 'Bottle builds must be dispatched from main, got %s\n' "${GITHUB_REF}" >&2
exit 1
}
info_file="$(mktemp)"
trap 'rm -f -- "${info_file}"' EXIT
brew info --json=v2 "${TAP}/${FORMULA}" >"${info_file}"
version="$(ruby -rjson -e '
formula = JSON.parse(File.read(ARGV.fetch(0))).fetch("formulae").first
version = formula.fetch("versions").fetch("stable")
revision = Integer(formula.fetch("revision", 0))
puts revision.positive? ? "#{version}_#{revision}" : version
' "${info_file}")"
[[ "${version}" =~ ^[0-9A-Za-z][0-9A-Za-z._+-]*$ ]] || {
printf 'Unsafe formula version: %s\n' "${version}" >&2
exit 1
}
[[ "${GITHUB_SHA}" =~ ^[0-9a-f]{40}$ ]] || {
printf 'Invalid GitHub commit SHA\n' >&2
exit 1
}
safe_formula="${FORMULA//@/-}"
artifact_name="bottle-${safe_formula}-${version}-${GITHUB_SHA::12}"
{
printf 'artifact_name=%s\n' "${artifact_name}"
printf 'version=%s\n' "${version}"
} >>"${GITHUB_OUTPUT}"

- name: Build from the pinned source
run: |
set -Eeuo pipefail
brew install --build-bottle "${TAP}/${FORMULA}"

- name: Run formula smoke test
run: brew test "${TAP}/${FORMULA}"

- name: Create bottle and metadata
run: |
set -Eeuo pipefail
root_url="https://ghcr.io/v2/${TAP}"
mkdir -p bottle-output
cd bottle-output
brew bottle --json --root-url="${root_url}" "${TAP}/${FORMULA}"

- name: Validate bottle artifact
id: artifact
env:
BOTTLE_VERSION: ${{ steps.metadata.outputs.version }}
run: |
set -Eeuo pipefail
root_url="https://ghcr.io/v2/${TAP}"
ruby scripts/validate-bottle-artifact.rb \
--directory bottle-output \
--formula "${FORMULA}" \
--tap "${TAP}" \
--version "${BOTTLE_VERSION}" \
--git-revision "${GITHUB_SHA}" \
--root-url "${root_url}" \
--github-output "${GITHUB_OUTPUT}"

- name: Upload bottle job artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: ${{ steps.metadata.outputs.artifact_name }}
path: |-
${{ steps.artifact.outputs.bottle_path }}
${{ steps.artifact.outputs.json_path }}
if-no-files-found: error
retention-days: 7

outputs:
artifact_name: ${{ steps.metadata.outputs.artifact_name }}
version: ${{ steps.metadata.outputs.version }}

publish:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: macos-14
permissions:
contents: write
packages: write
pull-requests: write
env:
FORMULA: ${{ inputs.formula }}
TAP: artagon/jdkvalhalla
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: false

- name: Set up Homebrew
uses: Homebrew/actions/setup-homebrew@b2a302b9a642580cae998e6ba2076ffd28e61317 # v5

- name: Download bottle job artifact
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: ${{ needs.build.outputs.artifact_name }}
path: bottle-artifact

- name: Validate bottle artifact
id: artifact
env:
BOTTLE_VERSION: ${{ needs.build.outputs.version }}
run: |
set -Eeuo pipefail
root_url="https://ghcr.io/v2/${TAP}"
ruby scripts/validate-bottle-artifact.rb \
--directory bottle-artifact \
--formula "${FORMULA}" \
--tap "${TAP}" \
--version "${BOTTLE_VERSION}" \
--git-revision "${GITHUB_SHA}" \
--root-url "${root_url}" \
--github-output "${GITHUB_OUTPUT}"

- name: Publish bottle package
env:
HOMEBREW_GITHUB_PACKAGES_TOKEN: ${{ github.token }}
HOMEBREW_GITHUB_PACKAGES_USER: ${{ github.repository_owner }}
run: |
set -Eeuo pipefail
cd bottle-artifact
brew pr-upload --upload-only --warn-on-upload-failure

- name: Verify anonymous bottle package
env:
BOTTLE_JSON: ${{ steps.artifact.outputs.json_path }}
BOTTLE_VERSION: ${{ needs.build.outputs.version }}
run: |
set -Eeuo pipefail
manifest_file="$(mktemp)"
trap 'rm -f -- "${manifest_file}"' EXIT
image_formula="${FORMULA%@*}/${FORMULA#*@}"
image="docker://ghcr.io/${TAP}/${image_formula}:${BOTTLE_VERSION}"
if ! skopeo inspect --raw "${image}" >"${manifest_file}"; then
printf '%s\n' \
'Bottle package is not anonymously readable.' \
'For a first publish, make the new GHCR package public and rerun this workflow.' >&2
exit 1
fi
ruby -rjson -e '
manifest = JSON.parse(File.read(ARGV.fetch(0)))
bottle = JSON.parse(File.read(ARGV.fetch(1))).values.fetch(0).fetch("bottle")
expected = bottle.fetch("tags").values.fetch(0).fetch("sha256")
descriptors = manifest.fetch("manifests")
abort "anonymous GHCR manifest must contain exactly one bottle" unless descriptors.one?
descriptor = descriptors.fetch(0)
valid = descriptor.dig("annotations", "sh.brew.bottle.digest") == expected &&
descriptor.dig("platform", "architecture") == "arm64" &&
descriptor.dig("platform", "os") == "darwin"
abort "anonymous GHCR manifest does not match the validated bottle" unless valid
' "${manifest_file}" "${BOTTLE_JSON}"

- name: Merge bottle metadata into formula
env:
BOTTLE_JSON: ${{ steps.artifact.outputs.json_path }}
run: |
set -Eeuo pipefail
brew untap "${TAP}" >/dev/null 2>&1 || true
brew tap --custom-remote "${TAP}" "${GITHUB_WORKSPACE}"
tap_root="$(brew --repository "${TAP}")"
brew bottle --merge --write --no-commit "${BOTTLE_JSON}"
cp "${tap_root}/Formula/${FORMULA}.rb" "Formula/${FORMULA}.rb"
if git diff --quiet -- "Formula/${FORMULA}.rb"; then
printf 'Bottle merge did not change Formula/%s.rb\n' "${FORMULA}" >&2
exit 1
fi

- name: Create bottle block pull request
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
with:
token: ${{ github.token }}
commit-message: >-
chore(formula): add ${{ inputs.formula }}
${{ needs.build.outputs.version }} bottle
title: >-
chore(formula): add ${{ inputs.formula }}
${{ needs.build.outputs.version }} bottle
body: |
Adds the Homebrew-generated bottle block for `${{ inputs.formula }}`
version `${{ needs.build.outputs.version }}`.

The bottle was built from the formula's pinned source, smoke-tested,
and published to the tap's GitHub Container Registry package.
branch: bottle/${{ needs.build.outputs.artifact_name }}
delete-branch: true
add-paths: Formula/${{ inputs.formula }}.rb
9 changes: 5 additions & 4 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ on:
- cron: '0 6 * * 1' # Weekly on Mondays at 6 AM UTC

permissions:
actions: read
contents: read
security-events: write

Expand All @@ -21,15 +20,17 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- name: Initialize CodeQL
uses: github/codeql-action/init@0f47cf5ea395a08f5ca3b81a506c66a63ecb648a # v3.31.0
uses: github/codeql-action/init@d198d2fabf39a7f36b5ce57ce70d4942944f006e # v3.31.0
with:
languages: 'ruby'
queries: +security-extended,security-and-quality

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@0f47cf5ea395a08f5ca3b81a506c66a63ecb648a # v3.31.0
uses: github/codeql-action/analyze@d198d2fabf39a7f36b5ce57ce70d4942944f006e # v3.31.0
with:
category: "/language:ruby"
Loading
Loading