Skip to content

Add GitHub Actions workflow to build Raspberry Pi image - #286

Open
0nly-Fir3 wants to merge 1 commit into
DouglasHalse:mainfrom
0nly-Fir3:fix/issue-165-rpi-image-workflow
Open

Add GitHub Actions workflow to build Raspberry Pi image#286
0nly-Fir3 wants to merge 1 commit into
DouglasHalse:mainfrom
0nly-Fir3:fix/issue-165-rpi-image-workflow

Conversation

@0nly-Fir3

Copy link
Copy Markdown
Contributor

Summary

This PR adds a GitHub Actions workflow to automatically build a pre-configured Raspberry Pi image.

Fixes #165

Changes

Added .github/workflows/build-rpi-image.yml that:

Features

  • 🍓 Creates a production-ready Raspberry Pi OS Lite image
  • 📦 Pre-installs SnackAttack and all dependencies
  • 🚀 Configures auto-login and auto-start on boot
  • 🔐 Enables SSH for remote access
  • 📤 Uploads compressed image as artifact
  • 🏷️ Attaches image to releases when published

How to use

  1. Go to Actions tab
  2. Select "Build Raspberry Pi Image"
  3. Click "Run workflow"
  4. Wait ~1-2 hours for the build
  5. Download the image from artifacts
  6. Flash to SD card with Raspberry Pi Imager

Default credentials

  • Username: pi
  • Password: snackattack

The image boots directly into SnackAttack without any desktop environment, as requested in the issue.

Fixes DouglasHalse#165

Added automated workflow that:
- Creates a production-ready Raspberry Pi OS Lite image
- Pre-installs SnackAttack and all dependencies
- Configures auto-login and auto-start on boot
- Enables SSH for remote access
- Can be triggered manually or on release
- Uploads compressed image as artifact

The image boots directly into SnackAttack without any desktop environment.
Copilot AI review requested due to automatic review settings December 12, 2025 10:16

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a GitHub Actions workflow to automate the creation of pre-configured Raspberry Pi OS images with SnackAttack pre-installed and configured for automatic startup.

  • Introduces workflow triggered manually or on release publication
  • Uses pi-gen to build custom Raspberry Pi OS Lite images with SnackAttack
  • Configures auto-login, SSH access, and automatic application launch

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

on_chroot << CHROOT
# Clone SnackAttack repository
cd /home/pi
git clone https://github.com/${{ github.repository }}.git snackAttackTrack

Copilot AI Dec 12, 2025

Copy link

Choose a reason for hiding this comment

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

Using 'git clone --depth 1' without specifying a branch or tag means the image will always contain the latest code from the default branch at build time, even for release builds. For release workflows, consider pinning to a specific commit SHA or tag to ensure reproducible builds and that release images contain the exact code version being released.

Suggested change
git clone https://github.com/${{ github.repository }}.git snackAttackTrack
git clone --depth 1 https://github.com/${{ github.repository }}.git snackAttackTrack
cd snackAttackTrack
git fetch --depth 1 origin ${{ github.sha }}
git checkout ${{ github.sha }}
cd ..

Copilot uses AI. Check for mistakes.
cat > /etc/systemd/system/getty@tty1.service.d/autologin.conf << EOF
[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin pi --noclear %I \\\$TERM

Copilot AI Dec 12, 2025

Copy link

Choose a reason for hiding this comment

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

The escape sequence '\$TERM' may not be correctly interpreted within the nested heredoc structure. This could result in the wrong value being written to the autologin configuration file, potentially breaking the auto-login functionality. Verify that the final configuration file contains the literal '$TERM' as intended.

Suggested change
ExecStart=-/sbin/agetty --autologin pi --noclear %I \\\$TERM
ExecStart=-/sbin/agetty --autologin pi --noclear %I \$TERM

Copilot uses AI. Check for mistakes.
Comment on lines +215 to +221
echo "IMAGE_PATH=pi-gen/deploy/${IMAGE_FILE}.xz" >> $GITHUB_ENV
echo "Image compressed: ${IMAGE_FILE}.xz"
else
echo "Looking for zip file..."
ZIP_FILE=$(ls *.zip 2>/dev/null | head -1)
if [ -n "$ZIP_FILE" ]; then
echo "IMAGE_PATH=pi-gen/deploy/$ZIP_FILE" >> $GITHUB_ENV

Copilot AI Dec 12, 2025

Copy link

Choose a reason for hiding this comment

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

The IMAGE_PATH environment variable is set but never used in subsequent steps. The artifact and release upload steps use glob patterns instead. Either remove this unused variable assignment or update the upload steps to reference it for more explicit and maintainable file path handling.

Copilot uses AI. Check for mistakes.
Comment on lines +99 to +102
cp ../rpi-setup/quick-deploy.sh stage2/99-snackattack/files/
cp ../rpi-setup/setup-autostart.sh stage2/99-snackattack/files/
cp ../rpi-setup/setup-production.sh stage2/99-snackattack/files/

Copilot AI Dec 12, 2025

Copy link

Choose a reason for hiding this comment

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

The workflow attempts to copy setup scripts from a non-existent 'rpi-setup' directory. These files (quick-deploy.sh, setup-autostart.sh, setup-production.sh) are not present in the repository, which will cause the build to fail immediately when executing these copy commands. Either remove these copy commands if the files are not needed, or ensure the required files are added to the repository before this workflow can function.

Suggested change
cp ../rpi-setup/quick-deploy.sh stage2/99-snackattack/files/
cp ../rpi-setup/setup-autostart.sh stage2/99-snackattack/files/
cp ../rpi-setup/setup-production.sh stage2/99-snackattack/files/

Copilot uses AI. Check for mistakes.
Comment on lines +10 to +18
pi_version:
description: 'Target Raspberry Pi version'
required: false
default: 'pi4'
type: choice
options:
- pi3
- pi4
- pi5

Copilot AI Dec 12, 2025

Copy link

Choose a reason for hiding this comment

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

The workflow defines a 'pi_version' input parameter but never uses it in the build process. All Raspberry Pi models (Pi 3, 4, and 5) would receive the same image regardless of the selection. If different hardware configurations are needed, the parameter should be used to configure pi-gen appropriately, or it should be removed to avoid confusion.

Suggested change
pi_version:
description: 'Target Raspberry Pi version'
required: false
default: 'pi4'
type: choice
options:
- pi3
- pi4
- pi5

Copilot uses AI. Check for mistakes.
Comment on lines +79 to +80
FIRST_USER_PASS="snackattack"
ENABLE_SSH=1

Copilot AI Dec 12, 2025

Copy link

Choose a reason for hiding this comment

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

The default password 'snackattack' is publicly documented in the PR description and hardcoded in the workflow. This creates a significant security risk as anyone can access the SSH service with known credentials. Consider implementing a secure password generation mechanism, prompting users to change the password on first boot, or at minimum documenting this as a critical security configuration step.

Copilot uses AI. Check for mistakes.
ZIP_FILE=$(ls *.zip 2>/dev/null | head -1)
if [ -n "$ZIP_FILE" ]; then
echo "IMAGE_PATH=pi-gen/deploy/$ZIP_FILE" >> $GITHUB_ENV
echo "Found zip: $ZIP_FILE"

Copilot AI Dec 12, 2025

Copy link

Choose a reason for hiding this comment

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

The 'Compress image' step does not handle the case where no image or zip file is found. If the build fails silently or produces output in an unexpected location, the step will complete successfully without setting IMAGE_PATH, and the subsequent upload steps will fail without a clear error message. Add error handling to fail explicitly if no image file is found.

Suggested change
echo "Found zip: $ZIP_FILE"
echo "Found zip: $ZIP_FILE"
else
echo "ERROR: No .img or .zip file found in pi-gen/deploy. Build failed." >&2
exit 1

Copilot uses AI. Check for mistakes.
Comment on lines +142 to +146
git clone https://github.com/${{ github.repository }}.git snackAttackTrack
chown -R 1000:1000 snackAttackTrack

# Install Python dependencies
cd snackAttackTrack

Copilot AI Dec 12, 2025

Copy link

Choose a reason for hiding this comment

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

The repository URL is dynamically constructed using github.repository, but the cloned directory name is hardcoded as 'snackAttackTrack'. If this workflow is ever used in a fork with a different repository name, the paths in subsequent steps (like line 181) would be incorrect. Consider using a consistent variable or the actual repository name from the context.

Suggested change
git clone https://github.com/${{ github.repository }}.git snackAttackTrack
chown -R 1000:1000 snackAttackTrack
# Install Python dependencies
cd snackAttackTrack
REPO_NAME="$(basename "${{ github.repository }}")"
git clone https://github.com/${{ github.repository }}.git "$REPO_NAME"
chown -R 1000:1000 "$REPO_NAME"
# Install Python dependencies
cd "$REPO_NAME"

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create a preloaded Raspberry pi image from Actions

2 participants