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
75 changes: 75 additions & 0 deletions .github/actions/niks3-push/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Push realized Nix closures to niks3
description: Push already-built Nix installables with a short-lived GitHub Actions OIDC token.
inputs:
installables:
description: Newline-delimited, already-realized Nix installables to push.
required: true
server-url:
description: niks3 write-plane URL.
required: true
max-concurrent-uploads:
description: niks3 client upload concurrency.
required: false
default: "30"
niks3-cli-flake-ref:
description: Immutable flake reference that provides the niks3 CLI package.
required: false
default: github:Mic92/niks3/bb87dcb1b46a1f0c9426b733f4fe325245e386fa#niks3
runs:
using: composite
steps:
- name: Push already-realized closures
shell: bash
env:
NIKS3_SERVER_URL: ${{ inputs.server-url }}
NIKS3_INSTALLABLES: ${{ inputs.installables }}
NIKS3_CLI_FLAKE_REF: ${{ inputs.niks3-cli-flake-ref }}
NIKS3_MAX_CONCURRENT: ${{ inputs.max-concurrent-uploads }}
run: |
set -euo pipefail

mapfile -t installables < <(printf '%s\n' "$NIKS3_INSTALLABLES" | sed '/^[[:space:]]*$/d')
if [ "${#installables[@]}" -eq 0 ]; then
echo "installables input is empty" >&2
exit 1
fi

# Deliberately do not build here. The caller must publish the exact closures that already
# passed its release gates on this runner.
paths_output="$(nix path-info "${installables[@]}")"
mapfile -t paths <<<"$paths_output"
if [ "${#paths[@]}" -ne "${#installables[@]}" ]; then
echo "resolved ${#paths[@]} store paths for ${#installables[@]} installables" >&2
exit 1
fi
for path in "${paths[@]}"; do
if [[ "$path" != /nix/store/* ]]; then
echo "nix path-info returned an invalid store path: $path" >&2
exit 1
fi
done

# Realize and validate the pinned client before minting the short-lived OIDC token.
niks3_cli_path="$(nix build "$NIKS3_CLI_FLAKE_REF" --no-link --print-out-paths)"
if [[ "$niks3_cli_path" != /nix/store/* ]] || [ ! -x "$niks3_cli_path/bin/niks3" ]; then
echo "niks3 CLI did not resolve to one executable store path: $niks3_cli_path" >&2
exit 1
fi

audience="$(jq -rn --arg value "$NIKS3_SERVER_URL" '$value | @uri')"
token="$(curl -fsSL \
-H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=${audience}" \
| jq -er '.value | select(type == "string" and length > 0)')"
echo "::add-mask::${token}"

umask 077
token_file="$(mktemp "${RUNNER_TEMP:-/tmp}/niks3-auth-token.XXXXXX")"
trap 'rm -f -- "$token_file"' EXIT
printf '%s' "$token" >"$token_file"
unset token

NIKS3_AUTH_TOKEN_FILE="$token_file" "$niks3_cli_path/bin/niks3" push \
--server-url "$NIKS3_SERVER_URL" \
--max-concurrent-uploads "$NIKS3_MAX_CONCURRENT" \
"${paths[@]}"
23 changes: 23 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
day: monday
time: "09:00"
timezone: America/Chicago
groups:
actions:
patterns: ["*"]
open-pull-requests-limit: 5
- package-ecosystem: nix
directory: /
schedule:
interval: monthly
time: "09:00"
timezone: America/Chicago
groups:
flake-inputs:
patterns: ["*"]
open-pull-requests-limit: 2
33 changes: 33 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: ci
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
verify:
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: DeterminateSystems/determinate-nix-action@61cbfe2efc2d4e7a8a6d56967c3c1058e846c858 # v3.21.9
with:
extra-conf: |
extra-substituters = https://cache.secbear.dev https://secbear-cache-niks3.fly.dev
extra-trusted-public-keys = cache.secbear.dev-1:Pbeqskasb4M7FrHn+/kfnv1PCSvF0cJhl1snZ13Jn20=
fallback = true
connect-timeout = 5
stalled-download-timeout = 15
require-sigs = true
- name: Evaluate every declared system
run: nix flake check --all-systems --no-build
- name: Format and statically validate repository files
run: nix build .#checks.x86_64-linux.treefmt --no-link --print-build-logs
79 changes: 66 additions & 13 deletions .github/workflows/niks3-push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ on:
description: niks3 write-plane URL.
required: true
type: string
substituter-url:
description: Space-separated signed Nix binary-cache URLs used before building.
required: true
type: string
substituter-public-key:
description: Public signing key for the Nix binary cache.
required: true
type: string
max-concurrent-uploads:
description: niks3 client upload concurrency.
required: false
Expand All @@ -19,10 +27,11 @@ on:
description: Flake reference that provides the niks3 CLI package.
required: false
type: string
default: github:Mic92/niks3/v1.4.0#niks3
default: github:Mic92/niks3/bb87dcb1b46a1f0c9426b733f4fe325245e386fa#niks3
jobs:
push:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
timeout-minutes: 60
permissions:
contents: read
id-token: write
Expand All @@ -33,9 +42,19 @@ jobs:
NIKS3_MAX_CONCURRENT: ${{ inputs.max-concurrent-uploads }}
steps:
- name: Check out repository
uses: actions/checkout@v4
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install Nix
uses: cachix/install-nix-action@v31
uses: DeterminateSystems/determinate-nix-action@61cbfe2efc2d4e7a8a6d56967c3c1058e846c858 # v3.21.9
with:
extra-conf: |
extra-substituters = ${{ inputs.substituter-url }}
extra-trusted-public-keys = ${{ inputs.substituter-public-key }}
fallback = true
connect-timeout = 5
stalled-download-timeout = 15
require-sigs = true
- name: Build requested installables
shell: bash
run: |
Expand All @@ -48,31 +67,65 @@ jobs:
exit 1
fi

nix build --no-link "${installables[@]}"
nix build --no-link --print-build-logs "${installables[@]}"
- name: Realize the pinned niks3 client before minting a token
id: cli
shell: bash
run: |
set -euo pipefail

cli_path="$(nix build "$NIKS3_CLI_FLAKE_REF" --no-link --print-out-paths)"
if [[ "$cli_path" != /nix/store/* ]] || [ ! -x "$cli_path/bin/niks3" ]; then
echo "niks3 CLI did not resolve to one executable store path: $cli_path" >&2
exit 1
fi
echo "path=${cli_path}" >> "$GITHUB_OUTPUT"
- name: Fetch OIDC token
id: oidc
shell: bash
run: |
set -euo pipefail

audience="$(jq -rn --arg value "$NIKS3_SERVER_URL" '$value | @uri')"
token="$(curl -fsSL \
-H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=${NIKS3_SERVER_URL}" \
| jq -r '.value')"
"${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=${audience}" \
| jq -er '.value | select(type == "string" and length > 0)')"
echo "::add-mask::${token}"
echo "token=${token}" >> "$GITHUB_OUTPUT"

umask 077
token_file="$RUNNER_TEMP/niks3-auth-token"
printf '%s' "$token" >"$token_file"
echo "token-file=${token_file}" >> "$GITHUB_OUTPUT"
- name: Push closures to niks3
shell: bash
env:
NIKS3_AUTH_TOKEN: ${{ steps.oidc.outputs.token }}
NIKS3_AUTH_TOKEN_FILE: ${{ steps.oidc.outputs.token-file }}
NIKS3_CLI_PATH: ${{ steps.cli.outputs.path }}
run: |
set -euo pipefail
trap 'rm -f -- "$NIKS3_AUTH_TOKEN_FILE"' EXIT

if [[ "$NIKS3_CLI_PATH" != /nix/store/* ]] || [ ! -x "$NIKS3_CLI_PATH/bin/niks3" ]; then
echo "niks3 CLI is missing or invalid: $NIKS3_CLI_PATH" >&2
exit 1
fi

mapfile -t installables < <(printf '%s\n' "$NIKS3_INSTALLABLES" | sed '/^[[:space:]]*$/d')
mapfile -t paths < <(nix path-info "${installables[@]}")
paths_output="$(nix path-info "${installables[@]}")"
mapfile -t paths <<<"$paths_output"
if [ "${#paths[@]}" -ne "${#installables[@]}" ]; then
echo "resolved ${#paths[@]} store paths for ${#installables[@]} installables" >&2
exit 1
fi
for path in "${paths[@]}"; do
if [[ "$path" != /nix/store/* ]]; then
echo "nix path-info returned an invalid store path: $path" >&2
exit 1
fi
done

nix shell "$NIKS3_CLI_FLAKE_REF" -c \
niks3 push \
"$NIKS3_CLI_PATH/bin/niks3" push \
--server-url "$NIKS3_SERVER_URL" \
--auth-token "$NIKS3_AUTH_TOKEN" \
--max-concurrent-uploads "$NIKS3_MAX_CONCURRENT" \
"${paths[@]}"
Loading