mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
* docs: design Linux frame-copy packaging * docs: plan Linux frame-copy packaging * feat(packaging): define Linux frame-copy profiles * fix(packaging): reject inherited profile names * feat(embedded-mpv): validate staged Linux runtime * fix(embedded-mpv): require Linux source packages * fix(embedded-mpv): harden Linux runtime staging * feat(embedded-mpv): build LGPL Linux runtime * fix(embedded-mpv): pin Linux runtime inputs * feat(embedded-mpv): build relocatable Linux helper * fix(embedded-mpv): require bundled Linux runtime * fix(embedded-mpv): make Linux runtime portable * feat(packaging): ship Linux frame-copy artifacts * fix(embedded-mpv): verify Linux helper linkage * fix(packaging): enforce Linux frame-copy isolation * fix(embedded-mpv): pin Linux display data * docs(embedded-mpv): document Linux frame-copy packaging * feat(embedded-mpv): probe Linux frame-copy runtime * test(embedded-mpv): smoke packaged Linux frame-copy * docs(embedded-mpv): clarify Linux system runtime baseline * fix(embedded-mpv): harden Linux runtime capability gate * ci: verify Linux frame-copy packages * test(embedded-mpv): harden packaged Linux smoke * test(embedded-mpv): preserve packaged GL mode * test(packaging): harden Linux package probes * fix(embedded-mpv): enable private Snap shared memory * fix(embedded-mpv): sanitize Linux helper environment * fix(packaging): enforce private Snap memory semantics * fix(packaging): reject ambiguous Snap memory metadata * fix(embedded-mpv): prioritize trusted Snap GL * fix(packaging): reject advanced Snap YAML semantics * fix(packaging): reject arbitrary Snap YAML aliases * feat(packaging): ship Linux runtime license notices * docs(embedded-mpv): document Linux runtime distribution * fix(packaging): parse Snap trailing comments safely * fix(release): gate Snap publish on public source release * fix(packaging): strip VCS metadata from source bundle * docs(packaging): clarify Linux source release gate * test(embedded-mpv): smoke missing bundled libmpv * style(embedded-mpv): format final validation inputs * fix(e2e): satisfy fixture index signature typing * fix(ci): declare fontconfig gperf generator * fix(embedded-mpv): hash runtime cache identities * fix(packaging): harden Linux frame-copy delivery * fix(packaging): tighten runtime delivery gates * fix(ci): decouple Linux runtime matrix * fix(packaging): harden Linux frame-copy delivery * fix(packaging): validate Linux frame-copy runtimes * fix(packaging): scope Snap Electron library checks * feat(packaging): ship Linux frame-copy runtimes * fix(packaging): improve Linux runtime smoke diagnostics * fix(packaging): expose bounded helper probe details * test(packaging): trace Snap EGL probe failures * fix(packaging): prefer core22 ABI in Snap helper * fix(packaging): bound helper probe capture * fix(packaging): harden Linux frame-copy releases * fix(packaging): canonicalize libplacebo submodule identity * fix(packaging): make source archive inspection portable * fix(packaging): harden Snap release verification
270 lines
13 KiB
YAML
270 lines
13 KiB
YAML
name: Publish Snap after public release
|
|
|
|
on:
|
|
release:
|
|
types:
|
|
- published
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
verify-snap:
|
|
name: Verify public-release Snap assets
|
|
if: ${{ startsWith(github.event.release.tag_name, 'v') && github.event.release.draft == false }}
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 45
|
|
env:
|
|
SOURCE_ARCHIVE_NAME: linux-frame-copy-runtime-sources.tar.xz
|
|
outputs:
|
|
receipt-sha256: ${{ steps.bind-transfer.outputs.receipt-sha256 }}
|
|
|
|
steps:
|
|
- name: Checkout released tooling
|
|
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
|
with:
|
|
ref: ${{ github.event.release.tag_name }}
|
|
persist-credentials: false
|
|
|
|
- name: Install release source verifier
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
sudo apt-get update
|
|
sudo apt-get install --no-install-recommends -y \
|
|
binutils \
|
|
squashfs-tools \
|
|
xz-utils
|
|
|
|
- name: Select exact public release assets
|
|
shell: bash
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
gh api \
|
|
--paginate \
|
|
--slurp \
|
|
"repos/${GITHUB_REPOSITORY}/releases/${{ github.event.release.id }}/assets?per_page=100" \
|
|
> "${RUNNER_TEMP}/snap-release-assets.json"
|
|
node tools/packaging/release-snap-assets.cjs select \
|
|
--assets-json "${RUNNER_TEMP}/snap-release-assets.json" \
|
|
--output-json "${RUNNER_TEMP}/selected-snap-release-assets.json"
|
|
|
|
- name: Download exact public release assets
|
|
shell: bash
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
ASSET_DIRECTORY="${RUNNER_TEMP}/snap-release-downloads"
|
|
rm -rf "${ASSET_DIRECTORY}"
|
|
mkdir -p "${ASSET_DIRECTORY}"
|
|
node -e \
|
|
"const fs=require('node:fs'); const selected=JSON.parse(fs.readFileSync(process.argv[1],'utf8')); for (const asset of [...selected.snapAssets, selected.sourceAsset]) console.log([asset.id, asset.name].join('\\t'));" \
|
|
"${RUNNER_TEMP}/selected-snap-release-assets.json" |
|
|
while IFS=$'\t' read -r ASSET_ID ASSET_NAME; do
|
|
gh api \
|
|
--header "Accept: application/octet-stream" \
|
|
"repos/${GITHUB_REPOSITORY}/releases/assets/${ASSET_ID}" \
|
|
> "${ASSET_DIRECTORY}/${ASSET_NAME}"
|
|
done
|
|
|
|
- name: Verify downloaded public release assets
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
VERIFIED_ASSET_STAGING="${RUNNER_TEMP}/verified-snap-release-assets"
|
|
SEALED_ASSET_PARENT="/var/lib/iptvnator-snap-release"
|
|
SEALED_ASSET_DIRECTORY="${SEALED_ASSET_PARENT}/assets"
|
|
test -s "${RUNNER_TEMP}/snap-release-downloads/${SOURCE_ARCHIVE_NAME}"
|
|
test ! -e "${VERIFIED_ASSET_STAGING}"
|
|
sudo test ! -e "${SEALED_ASSET_PARENT}"
|
|
node tools/packaging/release-snap-assets.cjs verify \
|
|
--manifest "${RUNNER_TEMP}/selected-snap-release-assets.json" \
|
|
--directory "${RUNNER_TEMP}/snap-release-downloads" \
|
|
--repository-revision "$(git rev-parse HEAD)" \
|
|
--verified-directory "${VERIFIED_ASSET_STAGING}"
|
|
sudo install -d -m 0700 -o root -g root "${SEALED_ASSET_PARENT}"
|
|
sudo mv "${VERIFIED_ASSET_STAGING}" "${SEALED_ASSET_DIRECTORY}"
|
|
sudo chown -R root:root "${SEALED_ASSET_DIRECTORY}"
|
|
sudo find "${SEALED_ASSET_DIRECTORY}" -type d -exec chmod 0555 {} +
|
|
sudo find "${SEALED_ASSET_DIRECTORY}" -type f -exec chmod 0444 {} +
|
|
sudo chmod 0555 "${SEALED_ASSET_PARENT}"
|
|
|
|
- name: Reverify sealed public release assets
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
VERIFIED_ASSET_DIRECTORY="/var/lib/iptvnator-snap-release/assets"
|
|
node tools/packaging/release-snap-assets.cjs verify-sealed \
|
|
--manifest "${RUNNER_TEMP}/selected-snap-release-assets.json" \
|
|
--directory "${VERIFIED_ASSET_DIRECTORY}" \
|
|
--receipt "${VERIFIED_ASSET_DIRECTORY}/verified-release-assets.json" \
|
|
--repository-revision "$(git rev-parse HEAD)"
|
|
|
|
- name: Bind verified release transfer
|
|
id: bind-transfer
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
RECEIPT_PATH="/var/lib/iptvnator-snap-release/assets/verified-release-assets.json"
|
|
RECEIPT_RECORD="$(/usr/bin/sha256sum --binary "${RECEIPT_PATH}")"
|
|
RECEIPT_SHA256="${RECEIPT_RECORD%% *}"
|
|
[[ "${RECEIPT_SHA256}" =~ ^[a-f0-9]{64}$ ]]
|
|
printf 'receipt-sha256=%s\n' "${RECEIPT_SHA256}" >> "${GITHUB_OUTPUT}"
|
|
|
|
- name: Transfer verified release assets
|
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
|
with:
|
|
name: verified-snap-release-assets
|
|
path: /var/lib/iptvnator-snap-release/assets
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
compression-level: 0
|
|
include-hidden-files: true
|
|
|
|
publish-snap:
|
|
name: Publish verified public-release Snap to edge
|
|
needs: verify-snap
|
|
if: ${{ needs.verify-snap.result == 'success' && startsWith(github.event.release.tag_name, 'v') && github.event.release.draft == false }}
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 20
|
|
|
|
steps:
|
|
- name: Download verified release assets
|
|
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
|
with:
|
|
name: verified-snap-release-assets
|
|
path: ${{ runner.temp }}/verified-snap-release-assets
|
|
|
|
- name: Seal transferred public release assets
|
|
shell: bash
|
|
env:
|
|
EXPECTED_RECEIPT_SHA256: ${{ needs.verify-snap.outputs.receipt-sha256 }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
TRANSFERRED_ASSET_DIRECTORY="${RUNNER_TEMP}/verified-snap-release-assets"
|
|
SEALED_ASSET_PARENT="/var/lib/iptvnator-snap-release"
|
|
SEALED_ASSET_DIRECTORY="${SEALED_ASSET_PARENT}/assets"
|
|
test -d "${TRANSFERRED_ASSET_DIRECTORY}"
|
|
test ! -L "${TRANSFERRED_ASSET_DIRECTORY}"
|
|
shopt -s nullglob dotglob
|
|
TRANSFERRED_FILES=("${TRANSFERRED_ASSET_DIRECTORY}"/*)
|
|
TRANSFERRED_SNAPS=("${TRANSFERRED_ASSET_DIRECTORY}"/*.snap)
|
|
test "${#TRANSFERRED_SNAPS[@]}" -gt 0
|
|
test "${#TRANSFERRED_FILES[@]}" -eq "$(( ${#TRANSFERRED_SNAPS[@]} + 2 ))"
|
|
test -f "${TRANSFERRED_ASSET_DIRECTORY}/linux-frame-copy-runtime-sources.tar.xz"
|
|
test ! -L "${TRANSFERRED_ASSET_DIRECTORY}/linux-frame-copy-runtime-sources.tar.xz"
|
|
test -f "${TRANSFERRED_ASSET_DIRECTORY}/verified-release-assets.json"
|
|
test ! -L "${TRANSFERRED_ASSET_DIRECTORY}/verified-release-assets.json"
|
|
for ASSET_FILE in "${TRANSFERRED_FILES[@]}"; do
|
|
test -f "${ASSET_FILE}"
|
|
test ! -L "${ASSET_FILE}"
|
|
done
|
|
RECEIPT_PATH="${TRANSFERRED_ASSET_DIRECTORY}/verified-release-assets.json"
|
|
RECEIPT_RECORD="$(/usr/bin/sha256sum --binary "${RECEIPT_PATH}")"
|
|
ACTUAL_RECEIPT_SHA256="${RECEIPT_RECORD%% *}"
|
|
[[ "${EXPECTED_RECEIPT_SHA256}" =~ ^[a-f0-9]{64}$ ]]
|
|
test "${ACTUAL_RECEIPT_SHA256}" = "${EXPECTED_RECEIPT_SHA256}"
|
|
/usr/bin/jq --exit-status '
|
|
type == "object" and
|
|
(keys == ["assets", "repositoryRevision", "schemaVersion"]) and
|
|
(.schemaVersion == 1) and
|
|
(.repositoryRevision |
|
|
type == "string" and test("^[a-f0-9]{40,64}$")) and
|
|
(.assets | type == "array" and length >= 2) and
|
|
(.assets | all(.[];
|
|
type == "object" and
|
|
(keys == ["id", "name", "sha256", "size"]) and
|
|
(.id |
|
|
type == "number" and . > 0 and
|
|
. <= 9007199254740991 and . == floor) and
|
|
(.name |
|
|
type == "string" and length > 0 and
|
|
. != "." and . != ".." and
|
|
(contains("/") | not) and
|
|
(contains("\\") | not) and
|
|
(explode | all(.[]; . > 31 and . != 127))) and
|
|
(.sha256 |
|
|
type == "string" and test("^[a-f0-9]{64}$")) and
|
|
(.size |
|
|
type == "number" and . > 0 and
|
|
. <= 9007199254740991 and . == floor))) and
|
|
([.assets[].name] | length == (unique | length)) and
|
|
([.assets[] |
|
|
select(.name == "linux-frame-copy-runtime-sources.tar.xz")] |
|
|
length == 1) and
|
|
([.assets[] | select(.name | endswith(".snap"))] |
|
|
length >= 1) and
|
|
(.assets | all(.[];
|
|
.name == "linux-frame-copy-runtime-sources.tar.xz" or
|
|
(.name | endswith(".snap"))))
|
|
' "${RECEIPT_PATH}" > /dev/null
|
|
RECEIPT_ASSET_COUNT="$(/usr/bin/jq --raw-output '.assets | length' "${RECEIPT_PATH}")"
|
|
test "${RECEIPT_ASSET_COUNT}" -eq "$(( ${#TRANSFERRED_SNAPS[@]} + 1 ))"
|
|
SIZE_MANIFEST="${RUNNER_TEMP}/verified-release-asset-sizes.tsv"
|
|
CHECKSUM_MANIFEST="${RUNNER_TEMP}/verified-release-asset-checksums.txt"
|
|
umask 077
|
|
/usr/bin/jq --raw-output \
|
|
'.assets[] | [.name, (.size | tostring)] | @tsv' \
|
|
"${RECEIPT_PATH}" > "${SIZE_MANIFEST}"
|
|
while IFS=$'\t' read -r ASSET_NAME EXPECTED_SIZE; do
|
|
ASSET_PATH="${TRANSFERRED_ASSET_DIRECTORY}/${ASSET_NAME}"
|
|
ACTUAL_SIZE="$(/usr/bin/stat --format=%s -- "${ASSET_PATH}")"
|
|
test "${ACTUAL_SIZE}" = "${EXPECTED_SIZE}"
|
|
done < "${SIZE_MANIFEST}"
|
|
/usr/bin/jq --raw-output \
|
|
'.assets[] | "\(.sha256) \(.name)"' \
|
|
"${RECEIPT_PATH}" > "${CHECKSUM_MANIFEST}"
|
|
(
|
|
cd "${TRANSFERRED_ASSET_DIRECTORY}"
|
|
/usr/bin/sha256sum --strict --check "${CHECKSUM_MANIFEST}"
|
|
)
|
|
rm -f "${SIZE_MANIFEST}" "${CHECKSUM_MANIFEST}"
|
|
shopt -u nullglob dotglob
|
|
sudo test ! -e "${SEALED_ASSET_PARENT}"
|
|
sudo install -d -m 0700 -o root -g root "${SEALED_ASSET_PARENT}"
|
|
sudo mv "${TRANSFERRED_ASSET_DIRECTORY}" "${SEALED_ASSET_DIRECTORY}"
|
|
sudo chown -R root:root "${SEALED_ASSET_DIRECTORY}"
|
|
sudo find "${SEALED_ASSET_DIRECTORY}" -type d -exec chmod 0555 {} +
|
|
sudo find "${SEALED_ASSET_DIRECTORY}" -type f -exec chmod 0444 {} +
|
|
sudo chmod 0555 "${SEALED_ASSET_PARENT}"
|
|
|
|
- name: Install Snapcraft
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
sudo snap install snapcraft --classic --channel=stable
|
|
|
|
- name: Publish all public-release snaps to edge
|
|
shell: bash
|
|
env:
|
|
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.snapcraft_token }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
VERIFIED_ASSET_DIRECTORY="/var/lib/iptvnator-snap-release/assets"
|
|
STORE_CREDENTIALS="${SNAPCRAFT_STORE_CREDENTIALS}"
|
|
unset SNAPCRAFT_STORE_CREDENTIALS
|
|
shopt -s nullglob dotglob
|
|
SNAP_FILES=("${VERIFIED_ASSET_DIRECTORY}"/*.snap)
|
|
test "${#SNAP_FILES[@]}" -gt 0
|
|
for SNAP_FILE in "${SNAP_FILES[@]}"; do
|
|
SNAP_NAME="${SNAP_FILE##*/}"
|
|
echo "Publishing public release asset: ${SNAP_NAME}"
|
|
# Candidate/stable promotion is manual after installed-Snap frame-copy and missing-runtime fallback smoke.
|
|
# GitHub Actions never promotes automatically.
|
|
SNAPCRAFT_STORE_CREDENTIALS="${STORE_CREDENTIALS}" /snap/bin/snapcraft upload --release=edge "${SNAP_FILE}"
|
|
done
|
|
unset STORE_CREDENTIALS
|
|
shopt -u nullglob dotglob
|