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
6 changes: 5 additions & 1 deletion release/install-relacs/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# Install relacs CLI

Downloads a [relacs](https://github.com/stackrox/relacs) release binary and
makes it available in `PATH` for subsequent workflow steps.
makes it available in a specified directory for subsequent workflow steps.

The binary is verified against the SHA-256 checksums published with each
release.

The installed binary is cached by runner and version.

## Recommended permissions

The action requires no special permissions.
Expand All @@ -18,6 +20,7 @@ permissions: {}

| Name | Required | Default | Description |
| --- | --- | --- | --- |
| `relacs_install_path` | no | `$HOME/.local/bin/relacs` | Path where to install `relacs` binary. Supports expansion of `$HOME` and `${HOME}` in custom paths (other environment variables are not expanded). |
| `token` | yes | | GH token to use for authentication for the `relacs` repository. |
| `version` | no | "" | Release version tag to install (e.g. `v0.4.2`). Omit to install the latest release. |

Expand All @@ -32,6 +35,7 @@ jobs:
steps:
- uses: stackrox/actions/release/install-relacs@v1
with:
relacs_install_path: /home/runner/.local/bin/relacs
token: ${{ secrets.RHACS_BOT_GITHUB_TOKEN }}
version: v0.4.2

Expand Down
76 changes: 74 additions & 2 deletions release/install-relacs/action.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
name: Install relacs CLI
description: Download relacs CLI from GitHub releases to ~/.local/bin
description: Download relacs CLI from GitHub releases to a specified directory

inputs:
relacs_install_path:
description: "Path where to install `relacs` binary. Defaults to `${HOME}/.local/bin/relacs`. Supports expansion of `$HOME` and `${HOME}` in custom paths (other environment variables are not expanded)."
required: false
default: ""
token:
description: "GitHub token to use for authentication"
required: true
Expand All @@ -13,11 +17,61 @@ inputs:
runs:
using: composite
steps:
- name: Download and install relacs
# Input defaults are literal strings; resolve $HOME in bash when unset.
# All other environment variables are intentionally not resolved due to security considerations.
- name: Resolve relacs install path
id: relacs-install-path
shell: bash
env:
RELACS_INSTALL_PATH: ${{ inputs.relacs_install_path }}
run: |
set -u
if [[ -z "${RELACS_INSTALL_PATH:-}" ]]; then
RELACS_INSTALL_PATH="${HOME}/.local/bin/relacs"
else
# Expand $HOME and ${HOME} while preserving variables like $HOME_SWEET_HOME.
# Note: \$ in double quotes becomes $ (end-of-line anchor) in sed, not a literal $.
RELACS_INSTALL_PATH="$(printf '%s' "${RELACS_INSTALL_PATH}" | sed \
-e "s|\${HOME}/|$HOME/|g" \
-e "s|\${HOME}\$|$HOME|g" \
-e "s|\$HOME/|$HOME/|g" \
-e "s|\$HOME\$|$HOME|g")"
Comment on lines +35 to +38

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm. Is it a real syntax $HOME$/blah and ${HOME}$/blah?
I know it's annoying but we should try make it right.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The $SOMETHING\$ in double quotes is interpreted to $SOMETHING$ in the sed expression, where the last $ is the end-of-line character.

$HOME$/blah would not be matched (and not be expanded), it's not a valid path.
Added a comment explaining the \$ intention.

Details
#!/bin/bash

echo "=== Demonstrating the sed pattern behavior ==="
echo ""

echo "Pattern: \"s|\$HOME\$|EXPANDED|g\" (in double quotes)"
echo ""

echo "Test 1: '\$HOME' (at end of string)"
echo '$HOME' | sed -e "s|\$HOME\$|EXPANDED|g"
echo ""

echo "Test 2: '\$HOME/bin' (followed by slash)"
echo '$HOME/bin' | sed -e "s|\$HOME\$|EXPANDED|g"
echo "  (no match - not at end of line)"
echo ""

echo "Test 3: '\$HOME\$' (literal dollar sign)"
echo '$HOME$' | sed -e "s|\$HOME\$|EXPANDED|g"
echo "  (no match - the \$ in pattern is end-of-line anchor, not literal $)"
echo ""

echo "=== Conclusion ==="
echo "The pattern \$HOME\$ in double quotes correctly matches:"
echo "  - \$HOME at the END of the string"
echo "  - NOT a literal \$HOME\$ with two dollar signs"
echo ""
echo "This is exactly what we want to:"
echo "  1. Expand '\$HOME' by itself"
echo "  2. Expand '\$HOME/some/path'"
echo "  3. NOT expand '\$HOME_SWEET_HOME' (different variable)"
- $HOME → expands ✅
- ${HOME} → expands ✅
- $HOME/bin → expands ✅
- ${HOME}/bin → expands ✅
- $HOME_SWEET_HOME/bin → does NOT expand ✅ (this is correct!)
- $HOME$/blah → does NOT expand ✅ (this is intended!)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I skipped Details in your reply because they strongly smell AI.

I get your idea is to prevent $HOME_SWEET_HOME by making sure that $HOME or ${HOME} is followed by a / slash or end of line. I doubt that the latter is valid case for $RELACS_INSTALL_PATH, but it's going to be the user's fault to set it to plain $HOME.

What blows my mind is that the last $ in $SOMETHING$ sed expression acts as the end-of-line match but the first $ does not. This absence of sed expression-level escaping for the first $ is quite confusing when just looking at this code.

Did you evaluate printf '%s' "$RELACS_INSTALL_PATH" | envsubst '$HOME' as the alternative to the approach with sed and why is it not good?

fi
echo "path=${RELACS_INSTALL_PATH}" | tee -a "${GITHUB_OUTPUT}"

# Detect desired or latest relacs version
- name: Get desired relacs version
id: relacs-version
shell: bash
env:
GH_TOKEN: ${{ inputs.token }}
VERSION: ${{ inputs.version }}
run: |
if [[ -n "${VERSION:-}" ]]; then
echo "Using version override: ${VERSION}"
else
VERSION="$(gh release view --repo stackrox/relacs --json tagName --jq .tagName)"
echo "Using actual latest version: ${VERSION}"
fi
echo "version=${VERSION}" | tee -a "${GITHUB_OUTPUT}"

# Restore relacs binary from cache to avoid re-downloading the same version
- name: Restore relacs binary from cache
id: get-relacs-from-cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # ratchet:actions/cache/restore@v6
with:
path: ${{ steps.relacs-install-path.outputs.path }}
key: relacs-${{ runner.os }}-${{ runner.arch }}-${{ steps.relacs-version.outputs.version }}

# Only install if cache missed
- name: Download and install relacs
id: install-relacs
if: steps.get-relacs-from-cache.outputs.cache-hit != 'true'
shell: bash
env:
RELACS_INSTALL_PATH: ${{ steps.relacs-install-path.outputs.path }}
GH_TOKEN: ${{ inputs.token }}
VERSION: ${{ steps.relacs-version.outputs.version }}
run: |
set -euo pipefail

Expand All @@ -31,3 +85,21 @@ runs:

# Execute installer with version from environment
bash "${INSTALLER}" "${VERSION}"

- name: Add relacs install path to PATH
shell: bash
env:
RELACS_INSTALL_PATH: ${{ steps.relacs-install-path.outputs.path }}
run: |
set -euo pipefail
relacs_path="$(dirname "${RELACS_INSTALL_PATH}")"
# Use printf to prevent command injection from the relacs_path variable
printf '%s\n' "${relacs_path}" | tee -a "${GITHUB_PATH}"

# Save cache only if install succeeded (prevents caching wrong version on install failure)
- name: Save relacs binary to cache
if: always() && steps.get-relacs-from-cache.outputs.cache-hit != 'true' && steps.install-relacs.outcome == 'success'
Comment thread
coderabbitai[bot] marked this conversation as resolved.
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # ratchet:actions/cache/save@v6
with:
path: ${{ steps.relacs-install-path.outputs.path }}
key: relacs-${{ runner.os }}-${{ runner.arch }}-${{ steps.relacs-version.outputs.version }}
Loading