Skip to content
This repository was archived by the owner on Apr 15, 2026. It is now read-only.
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
97 changes: 97 additions & 0 deletions .github/workflows/images-sync.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: Sync Images

on:
push:
branches: [master]
paths:
- 'images/**'
pull_request:
paths:
- 'images/**'
workflow_dispatch:
inputs:
force:
description: 'Force re-upload all images'
type: boolean
default: false
prune:
description: 'Run prune after sync'
type: boolean
default: false

concurrency:
group: images-sync-${{ github.ref }}
cancel-in-progress: false

permissions:
contents: write
pull-requests: write

jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-go@v5
with:
go-version: '1.23'
cache-dependency-path: tools/labctl/go.sum

- name: Build labctl
run: |
cd tools/labctl
go build -o ../../labctl .

- name: Install SOPS
if: github.event_name != 'pull_request'
run: |
curl -LO https://github.com/getsops/sops/releases/download/v3.9.2/sops-v3.9.2.linux.amd64
chmod +x sops-v3.9.2.linux.amd64
sudo mv sops-v3.9.2.linux.amd64 /usr/local/bin/sops

- name: Write SOPS age key
if: github.event_name != 'pull_request'
run: |
echo "${{ secrets.SOPS_AGE_KEY }}" > /tmp/age-key.txt
chmod 600 /tmp/age-key.txt

# PR: validate manifest only (no credentials needed)
- name: Validate Manifest (PR)
if: github.event_name == 'pull_request'
run: ./labctl images validate

# Push/dispatch: full sync with credentials
- name: Sync Images
if: github.event_name != 'pull_request'
id: sync
run: |
FLAGS=""
if [ "${{ inputs.force }}" == "true" ]; then FLAGS="--force"; fi

./labctl images sync \
--credentials images/e2.sops.yaml \
--sops-age-key-file /tmp/age-key.txt \
$FLAGS

- name: Create PR if files changed
if: github.event_name == 'push' && steps.sync.outputs.files_changed == 'true'
uses: peter-evans/create-pull-request@v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: 'chore: update source image references'
title: 'chore: update source image references'
body: |
Automated update of source image references.

Updated by `labctl images sync`.
branch: automated/image-updates
labels: automated
delete-branch: true

- name: Prune Orphaned Images
if: github.event_name != 'pull_request' && inputs.prune == true
run: |
./labctl images prune \
--credentials images/e2.sops.yaml \
--sops-age-key-file /tmp/age-key.txt
138 changes: 138 additions & 0 deletions .github/workflows/packer-vyos.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# TODO: Migrate to vyos-build (https://github.com/vyos/vyos-build) for building
# VyOS images instead of Packer. The vyos-build approach provides better support
# for customization and doesn't require nested virtualization in CI.
#
# This workflow is currently disabled pending the migration.

name: Build VyOS Image

# Disabled: triggers commented out pending vyos-build migration
# on:
# push:
# branches: [master]
# paths:
# - 'infrastructure/network/vyos/packer/**'
# pull_request:
# paths:
# - 'infrastructure/network/vyos/packer/**'
# workflow_dispatch:

on:
workflow_dispatch:
inputs:
note:
description: 'Workflow disabled - see TODO comment at top of file'
type: string
default: 'disabled'

# concurrency:
# group: packer-vyos-${{ github.ref }}
# cancel-in-progress: false

jobs:
disabled:
if: false
runs-on: ubuntu-latest
steps:
- run: echo "Workflow disabled pending vyos-build migration"

# Historical reference - Packer-based build workflow:
#
# validate:
# runs-on: warp-ubuntu-latest-x64-8x
# steps:
# - uses: actions/checkout@v4
#
# - uses: hashicorp/setup-packer@v3.1.0
# with:
# version: '1.11.2'
#
# - name: Packer Init
# working-directory: infrastructure/network/vyos/packer
# run: packer init .
#
# - name: Packer Validate
# working-directory: infrastructure/network/vyos/packer
# run: |
# # Validate with dummy values for required vars without defaults
# # Note: vyos_iso_url/checksum come from source.auto.pkrvars.hcl (auto-loaded)
# packer validate \
# -var "ssh_key_type=ssh-ed25519" \
# -var "ssh_public_key=AAAA" \
# .
#
# build:
# if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
# runs-on: warp-ubuntu-latest-x64-8x
# needs: validate
# steps:
# - uses: actions/checkout@v4
#
# - uses: actions/setup-go@v5
# with:
# go-version: '1.23'
# cache-dependency-path: tools/labctl/go.sum
#
# - name: Build labctl
# run: |
# cd tools/labctl
# go build -o ../../labctl .
#
# - name: Install SOPS
# run: |
# curl -LO https://github.com/getsops/sops/releases/download/v3.9.2/sops-v3.9.2.linux.amd64
# chmod +x sops-v3.9.2.linux.amd64
# sudo mv sops-v3.9.2.linux.amd64 /usr/local/bin/sops
#
# - name: Write SOPS age key
# run: |
# echo "${{ secrets.SOPS_AGE_KEY }}" > /tmp/age-key.txt
# chmod 600 /tmp/age-key.txt
#
# - name: Extract SSH public key
# env:
# SOPS_AGE_KEY_FILE: /tmp/age-key.txt
# run: |
# sops --decrypt \
# --extract '["ssh_public_key"]' images/packer-ssh.sops.yaml > /tmp/ssh_key.pub
#
# - name: Install QEMU
# run: |
# sudo apt-get update
# sudo apt-get install -y qemu-system-x86 qemu-utils
#
# - name: Enable KVM access
# run: |
# echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
# sudo udevadm control --reload-rules
# sudo udevadm trigger --name-match=kvm
# sudo usermod -aG kvm $USER
# sudo chmod 666 /dev/kvm || true
#
# - uses: hashicorp/setup-packer@v3.1.0
# with:
# version: '1.11.2'
#
# - name: Packer Init
# working-directory: infrastructure/network/vyos/packer
# run: packer init .
#
# - name: Packer Build
# working-directory: infrastructure/network/vyos/packer
# run: |
# # Extract key type and body from public key
# # Note: vyos_iso_url/checksum auto-loaded from source.auto.pkrvars.hcl
# SSH_KEY_TYPE=$(awk '{print $1}' /tmp/ssh_key.pub)
# SSH_KEY_BODY=$(awk '{print $2}' /tmp/ssh_key.pub)
# packer build \
# -var "ssh_key_type=${SSH_KEY_TYPE}" \
# -var "ssh_public_key=${SSH_KEY_BODY}" \
# .
#
# - name: Upload to e2
# run: |
# ./labctl images upload \
# --credentials images/e2.sops.yaml \
# --sops-age-key-file /tmp/age-key.txt \
# --source infrastructure/network/vyos/packer/output/vyos-lab.raw \
# --destination vyos/vyos-gateway.raw
17 changes: 17 additions & 0 deletions .mergify.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# TODO: Once vyos-build workflow is implemented, add check-success condition
# to verify the VyOS build before auto-merging image update PRs.

pull_request_rules:
- name: Auto-merge automated image updates
conditions:
- author=github-actions[bot]
- label=automated
- base=master
- "#approved-reviews-by>=0"
actions:
merge:
method: squash
commit_message_template: |
{{ title }}

{{ body }}
36 changes: 18 additions & 18 deletions images/e2.sops.yaml
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
access_key: ENC[AES256_GCM,data:2umSrpnNWg1Z/F4THPwnqA529qA=,iv:s+IusD2M/GkDILSmIeU9O6d9BcOCwFKv2ioMAWWnQxk=,tag:udWIa/WYwyYIGpiRUo0m8w==,type:str]
secret_key: ENC[AES256_GCM,data:Lwjs2u64QbX/DEkipUiq8XzP+xP27k7CnSRm2gs64EjWROuF6JSMvQ==,iv:cnO7A7UxCwKclt401BtUE/3nY1uvNhnClu0Upo+xcSg=,tag:bDvbTC0hXcnGNmZPrXLJIQ==,type:str]
endpoint: s3.us-west-1.idrivee2.com
bucket: provisioning
access_key: ENC[AES256_GCM,data:O33rmWp1jLBpsMm7/YqjHLJyaV0=,iv:fWoChZ+t5g8Eie/2Azp0sK28oB8Z0NXaZPlGXUoL0ME=,tag:3dXoEZWO2xstUHLntgN7Xw==,type:str]
secret_key: ENC[AES256_GCM,data:VPtl+wfbMCgj9lC7AvN+d/ifdE+EurAnVrmsCq8T74RlEP1QWAry1A==,iv:3hlYNxvvhY4bhW8thMtT00fDZsPUd0LGugSLs1sRKnM=,tag:kR+akUTyODwFHqaWXFPjCg==,type:str]
endpoint: ENC[AES256_GCM,data:kvtqTVSjychwy9PY7U9IL8bD6d+hcDZg6sE7rEr0zUGZ,iv:vuf01bAH7XvlJwoGSv4BAOfgJDvbx2NO5Yk40Wqj8yo=,tag:V3pNe2+nFLGfe0FTE04bjg==,type:str]
bucket: ENC[AES256_GCM,data:syQNZMQci1VPV00D,iv:M2srbHnS8X72zYIrWQMVywH08uDiIdFlA8NqngCOUrU=,tag:Vi1RcWzc563YW0nO0zs+cw==,type:str]
sops:
age:
- recipient: age1d9n4x345xfahp0wmjak4gjzawpjvmcxmyf5knct7yy84mznq2sdqp0dy2d
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBhTHNoLytHYUpBYmxYaWlt
WTV2S2lEUXZqMnFTcWFzUG91c3JTWXRVM2dBClVrKzF5eHo2N1F3L256T3VqLzNj
b2tBM0lvM2ZiOUw0d21yM2FJN2hCMjAKLS0tIDh5c0phUEZPQi9PSE4zb3oyZ25Q
bjRYeEtEUVd1MVBzUmV3eVVPT2FJYTgKH95crCdvD+NnA6MtlZfLfyooY7HBDlQn
zO5i3kjcxby2cuGTdpL3P3qq9DCCJ32dXajVPq7rFElqxDQmRv/uWQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWRHNkK2lock5NallTWWxh
VEJ6NHAzQ28xQTU2TDErTWttVjlHYzFVYWhNCkE1WWo2ZnhwL3ZjQTk4azh2RDdl
dDVBS2VLQy9zQTY1L0hSTk1qbzlSSmsKLS0tIHZKOEdVdHNnQy9jdTUwb3dpMU1M
a09BeDcwd2VPa2FyRjNHdlV2TFozeWMKw5RtkQxeXqP0K8tzAAtKsNhLSse0FEDZ
+imP4X0F1dmllr19MZUpTh1TU505usmY1YpIUMo4xos/9svc5x1qWw==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2025-12-20T06:07:03Z"
mac: ENC[AES256_GCM,data:S3J3+HCyfnn2dbPgCDS2tFbSGKvxcDLJl1xSd/6lh5qgwaOFGH8r8rJBt3iC4JrBIquu7A4xIFzumFpe/5cfRyyc/CgOjlbUl5ylrNyZrwjAIJTSsgd3jKfvn6p8UyDWrlNaNrLuQn3BxObKYV0qL//v8ZXKMKKM9QHjIUgjgww=,iv:g68vsNFRhcb1039EWTTd31zG+j4ld0FrKWIDnfYE9vY=,tag:1X4Y7watmWqy7t93W5pbUA==,type:str]
lastmodified: "2025-12-20T06:33:06Z"
mac: ENC[AES256_GCM,data:j0Rh4NvVILtGhck94NLsyvHgHupF4SPEznVV8p/4uqlAgS05iURkAblJKnUIK0Ch3MDShSF6kGGqDva88a9Af02wAiy4fBqzzLM8RIF0nYzXdLn0RK2SeFDkB5uC6Ae0jJ36HtjetprDyQTVXTVpoojq7fJWiNMz7FwopkWmcvE=,iv:ydNz6E0nIXk+FhclVZWcjoHRVeJA/zlnwCvrWIKLOIc=,tag:J8he0z5Ard0eFJHeOWYYOg==,type:str]
pgp:
- created_at: "2025-12-20T06:06:04Z"
- created_at: "2025-12-20T06:33:06Z"
enc: |-
-----BEGIN PGP MESSAGE-----

hF4DhYpGbIWgl5wSAQdA7WWkTJsZwJlD0iuCowi3CijlWrFhwPoh65VfT09Rimgw
osO38nxkM5tMWsbTsGp781OepdGbnepoJv8HCXbaVFMJZNOTo1lGviSUz+9bSArP
0lwBWrR4wsSr5TGk8qe7AJ3w8gabG13KJs4JXXVXdwXO00znq4FvSU8Sw5vD0Vmp
iK3Uq832Mij03gaEQPfMqXVmXMnrxdT56LS3qUqwzMa7srMrSWeB2R7D1l+lwQ==
=+0NA
hF4DhYpGbIWgl5wSAQdAYxP5cB5Uum2gpgLdjK/LD98NwDSfvKqqpOQQt8QkWQMw
nM9Czjci1spTfb9qIguwOJfdWtRYXwPFzmyxj2niRE+JXqGAXmhgKVZ1h69FRIct
0l4B3mt/VoWoLkJD52BiV32hcMwtlkK2D+g9tL2eNrBEZL01cuHs4CIy7nief1n3
kzzn+hrtCGVuwaO1joc+3wx0qkajVJ2X6RBfuzxVQBW40bFgAAdZl6t6dnJUATeX
=+q8v
-----END PGP MESSAGE-----
fp: 3965F16E293466CFE77D47F38C15553EEB22DB2A
encrypted_regex: ^(access_key|secret_key)$
unencrypted_suffix: _unencrypted
version: 3.11.0