ci: least-privilege release publishing, no persisted tokens, pinned audit, checksums
- Release Builds: the build/test matrix ran ~1,400 third-party build scripts and tests with a contents:write token persisted in .git/config. It now runs with contents:read and persist-credentials: false; a separate publish job (no project or dependency code) downloads the artefacts, writes SHA256SUMS and attaches both to the release. The release now waits for every platform instead of publishing partially. - CI/Fuzz checkouts don't persist credentials; cargo-audit is pinned (0.22.2), fails on yanked crates, and also audits fuzz/Cargo.lock; fuzz runs set -timeout=10 so slow-input bugs (like the IRC OSC one) are reported instead of hiding under libFuzzer's 20-minute default. - updates/index.php: array-valued query parameters no longer raise TypeErrors/warnings; nosniff header.
This commit is contained in:
@@ -22,6 +22,8 @@ jobs:
|
|||||||
working-directory: rust
|
working-directory: rust
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
- name: Linux dependencies (GUI libs, and sshd for the SSH integration tests)
|
- name: Linux dependencies (GUI libs, and sshd for the SSH integration tests)
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
run: |
|
run: |
|
||||||
@@ -39,6 +41,10 @@ jobs:
|
|||||||
working-directory: rust
|
working-directory: rust
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
||||||
- run: cargo install cargo-audit --locked
|
with:
|
||||||
# Ignored advisories and their reasons live in rust/.cargo/audit.toml.
|
persist-credentials: false
|
||||||
- run: cargo audit
|
- run: cargo install cargo-audit --version 0.22.2 --locked
|
||||||
|
# Ignored advisories and their reasons live in rust/.cargo/audit.toml. Yanked crates
|
||||||
|
# fail the build; the fuzz workspace has its own lockfile, so it's audited too.
|
||||||
|
- run: cargo audit --deny yanked
|
||||||
|
- run: cargo audit --deny yanked --file fuzz/Cargo.lock
|
||||||
|
|||||||
@@ -21,10 +21,12 @@ jobs:
|
|||||||
working-directory: rust/fuzz
|
working-directory: rust/fuzz
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
- run: sudo apt-get update && sudo apt-get install -y libasound2-dev
|
- run: sudo apt-get update && sudo apt-get install -y libasound2-dev
|
||||||
- run: rustup toolchain install nightly --profile minimal
|
- run: rustup toolchain install nightly --profile minimal
|
||||||
- run: cargo +nightly install cargo-fuzz --locked
|
- run: cargo +nightly install cargo-fuzz --locked
|
||||||
- run: cargo +nightly fuzz run ${{ matrix.target }} -- -max_total_time=120 -rss_limit_mb=2048
|
- run: cargo +nightly fuzz run ${{ matrix.target }} -- -max_total_time=120 -rss_limit_mb=2048 -timeout=10
|
||||||
- name: Upload crashing inputs
|
- name: Upload crashing inputs
|
||||||
if: failure()
|
if: failure()
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ on:
|
|||||||
- "v*"
|
- "v*"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# Building and testing runs every dependency's build scripts and tests, so those jobs only get a
|
||||||
|
# read token. Publishing is a separate job that never runs project or dependency code.
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -31,6 +33,7 @@ jobs:
|
|||||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Rust toolchain (pinned by rust-toolchain.toml)
|
- name: Rust toolchain (pinned by rust-toolchain.toml)
|
||||||
run: rustup show active-toolchain || rustup toolchain install
|
run: rustup show active-toolchain || rustup toolchain install
|
||||||
@@ -59,8 +62,26 @@ jobs:
|
|||||||
build/releases/manifest-*.json
|
build/releases/manifest-*.json
|
||||||
build/releases/version-*.txt
|
build/releases/version-*.txt
|
||||||
|
|
||||||
- name: Attach to GitHub Release
|
publish:
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
name: Attach to GitHub Release
|
||||||
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2
|
needs: build
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||||
with:
|
with:
|
||||||
files: build/releases/*/NexusTerminal-*.zip
|
path: artefacts
|
||||||
|
- name: Checksums
|
||||||
|
run: |
|
||||||
|
find artefacts -name 'NexusTerminal-*.zip' | while read -r f; do
|
||||||
|
(cd "$(dirname "$f")" && sha256sum "$(basename "$f")")
|
||||||
|
done > SHA256SUMS
|
||||||
|
cat SHA256SUMS
|
||||||
|
- uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
artefacts/*/*/NexusTerminal-*.zip
|
||||||
|
artefacts/*/NexusTerminal-*.zip
|
||||||
|
SHA256SUMS
|
||||||
|
|||||||
+6
-3
@@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
$platform = isset($_GET['platform']) ? $_GET['platform'] : '';
|
// Query parameters may arrive as arrays (?arch[]=x); treat anything but a string as absent.
|
||||||
$arch = isset($_GET['arch']) ? $_GET['arch'] : '';
|
$param = function ($name) { return isset($_GET[$name]) && is_string($_GET[$name]) ? $_GET[$name] : ''; };
|
||||||
|
$platform = $param('platform');
|
||||||
|
$arch = $param('arch');
|
||||||
$platform = preg_replace('/[^a-z0-9_-]/i', '', $platform);
|
$platform = preg_replace('/[^a-z0-9_-]/i', '', $platform);
|
||||||
$arch = preg_replace('/[^a-z0-9_-]/i', '', $arch);
|
$arch = preg_replace('/[^a-z0-9_-]/i', '', $arch);
|
||||||
|
|
||||||
@@ -13,7 +15,8 @@ if ($platform && $arch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$accept = isset($_SERVER['HTTP_ACCEPT']) ? $_SERVER['HTTP_ACCEPT'] : '';
|
$accept = isset($_SERVER['HTTP_ACCEPT']) ? $_SERVER['HTTP_ACCEPT'] : '';
|
||||||
$format = isset($_GET['format']) ? strtolower($_GET['format']) : '';
|
$format = strtolower($param('format'));
|
||||||
|
header('X-Content-Type-Options: nosniff');
|
||||||
|
|
||||||
$wantsJson = $format === 'json' || strpos($accept, 'application/json') !== false;
|
$wantsJson = $format === 'json' || strpos($accept, 'application/json') !== false;
|
||||||
$wantsVersion = $format === 'version';
|
$wantsVersion = $format === 'version';
|
||||||
|
|||||||
Reference in New Issue
Block a user