-
Notifications
You must be signed in to change notification settings - Fork 0
Modernize Docker-Prep for VM-Setup pinned launches #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| name: Release | ||
|
|
||
| on: | ||
| push: | ||
| tags: | ||
| - "v*" | ||
|
|
||
| permissions: | ||
| contents: write | ||
|
|
||
| jobs: | ||
| release: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - name: Resolve version | ||
| id: version | ||
| run: | | ||
| set -euo pipefail | ||
| tag="${GITHUB_REF_NAME}" | ||
| version_from_script=$(awk -F= '/^VERSION=/{ gsub(/"/, "", $2); print $2; exit }' install.sh) | ||
| echo "tag=$tag" >> "$GITHUB_OUTPUT" | ||
| echo "script_version=$version_from_script" >> "$GITHUB_OUTPUT" | ||
| if [[ "$tag" != "v${version_from_script}" ]]; then | ||
| echo "Tag $tag does not match install.sh VERSION=$version_from_script" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| - name: Create GitHub Release | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| TAG: ${{ steps.version.outputs.tag }} | ||
| run: | | ||
| set -euo pipefail | ||
| notes_file=$(mktemp) | ||
| cat > "$notes_file" <<EOF | ||
| ## Docker-Prep ${TAG} | ||
|
|
||
| Pinned consumer note: VM-Setup syncs this release through its | ||
| Sync Docker-Prep pin workflow. | ||
|
|
||
| Entrypoint: bash install.sh | ||
| Ephemeral launch env: | ||
| - DOCKER_PREP_EPHEMERAL=1 | ||
| - DOCKER_PREP_REVISION=<commit sha> | ||
| EOF | ||
| gh release create "$TAG" \ | ||
| --title "Docker-Prep ${TAG}" \ | ||
| --notes-file "$notes_file" | ||
|
|
||
| - name: Notify VM-Setup pin sync | ||
| env: | ||
| GH_TOKEN: ${{ secrets.VM_SETUP_DISPATCH_TOKEN }} | ||
| TAG: ${{ steps.version.outputs.tag }} | ||
| run: | | ||
| set -euo pipefail | ||
| if [[ -z "${GH_TOKEN:-}" ]]; then | ||
| echo "VM_SETUP_DISPATCH_TOKEN not configured; skipping repository_dispatch." | ||
| exit 0 | ||
| fi | ||
| gh api \ | ||
| --method POST \ | ||
| -H "Accept: application/vnd.github+json" \ | ||
| "/repos/Narehood/VM-Setup/dispatches" \ | ||
| -f event_type='docker-prep-release' \ | ||
| -f "client_payload[tag]=${TAG}" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| name: Shell security checks | ||
|
|
||
| on: | ||
| push: | ||
| pull_request: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| validate: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - name: Install analysis tools | ||
| run: sudo apt-get update && sudo apt-get install -y shellcheck ripgrep | ||
|
|
||
| - name: Validate syntax and security policy | ||
| run: bash tests/security-checks.sh | ||
|
|
||
| - name: Run ShellCheck | ||
| run: | | ||
| shellcheck --severity=error \ | ||
| install.sh \ | ||
| Scripts/*.sh \ | ||
| tests/*.sh \ | ||
| tools/*.sh | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| .docker-prep-pin-update.md | ||
| *.swp | ||
| *~ | ||
| .DS_Store |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| 7765e55bf2bd3e269ac078f7e1a10c013a0c04a6c53282f372746342cd326181 DockerGroup.sh | ||
| ff5479ac784e1e93c4fb7094cbba4d75e2188fb7fd10294166f26376052caa68 portainer-install.sh | ||
| bd647935533e2354db2ba0c2386ba3ea6c6222feed629c55048bcc0eae872f8a serverSetup.sh | ||
| dece1be99a98476bbcebdc745123a265b7bf313c8bf3191fb5ac98c2011fb52b UserCreation.sh |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,16 @@ | ||
| #!/bin/bash | ||
| set -euo pipefail | ||
|
|
||
| # Portainer CE Installation Script | ||
| # Deploys Portainer using the official LTS compose file | ||
| # Version: 1.1.0 | ||
| # Version: 1.2.0 | ||
| # DESCRIPTION: Install Portainer CE using the official LTS compose file | ||
|
|
||
| # DIRECTORY ANCHOR | ||
| SCRIPT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}")" | ||
| SCRIPT_DIR="$(dirname "$SCRIPT_PATH")" | ||
| readonly PORTAINER_IMAGE="portainer/portainer-ce:lts" | ||
| SUDO="" | ||
|
|
||
| # VISUAL STYLING | ||
| RED='\033[0;31m' | ||
|
|
@@ -155,31 +159,51 @@ check_existing_portainer() { | |
| return 0 | ||
| } | ||
|
|
||
| # pin_portainer_image rewrites floating Portainer image tags to the pinned LTS tag. | ||
| pin_portainer_image() { | ||
| local compose_file="$1" | ||
|
|
||
| print_info "Pinning Portainer image to ${PORTAINER_IMAGE}..." | ||
| if ! $SUDO grep -qE 'image:[[:space:]]*"?portainer/portainer-ce' "$compose_file"; then | ||
| print_error "Compose file does not reference official Portainer CE image." | ||
| return 1 | ||
| fi | ||
|
|
||
| $SUDO sed -i -E 's|(image:[[:space:]]*"?)portainer/portainer-ce(:[A-Za-z0-9._-]+)?("?)|\1'"${PORTAINER_IMAGE}"'\3|' "$compose_file" | ||
| if ! $SUDO grep -qE 'image:[[:space:]]*"?portainer/portainer-ce:lts"?$' "$compose_file"; then | ||
| print_error "Failed to pin Portainer image tag." | ||
| return 1 | ||
| fi | ||
|
|
||
| print_success "Portainer image pinned." | ||
| return 0 | ||
| } | ||
|
|
||
| # validate_compose_file validates a Docker Compose file for Portainer by checking that the file exists and is non-empty, contains a Portainer service and the official `portainer/portainer-ce` image reference, and has valid YAML syntax according to `docker compose config`; returns 0 on success and 1 on failure. | ||
| validate_compose_file() { | ||
| local compose_file="$1" | ||
|
|
||
| print_info "Validating compose file..." | ||
|
|
||
| if [ ! -f "$compose_file" ]; then | ||
| if [[ ! -f "$compose_file" ]]; then | ||
| print_error "Compose file not found." | ||
| return 1 | ||
| fi | ||
|
|
||
| if [ ! -s "$compose_file" ]; then | ||
| if [[ ! -s "$compose_file" ]]; then | ||
| print_error "Compose file is empty." | ||
| return 1 | ||
| fi | ||
|
|
||
| # Check for expected Portainer service definition | ||
| if ! grep -q "portainer" "$compose_file"; then | ||
| if ! $SUDO grep -q "portainer" "$compose_file"; then | ||
| print_error "Compose file does not contain expected Portainer service." | ||
| return 1 | ||
| fi | ||
|
|
||
| # Check for portainer image reference | ||
| if ! grep -qE "portainer/portainer-ce" "$compose_file"; then | ||
| print_error "Compose file does not reference official Portainer CE image." | ||
| # Check for pinned portainer image reference | ||
| if ! $SUDO grep -qE "image:[[:space:]]*\"?portainer/portainer-ce:lts\"?" "$compose_file"; then | ||
| print_error "Compose file does not reference pinned Portainer CE LTS image." | ||
| return 1 | ||
| fi | ||
|
|
||
|
|
@@ -202,8 +226,8 @@ deploy_portainer() { | |
| echo "" | ||
| print_info "Deploying Portainer CE (LTS)..." | ||
|
|
||
| if [ ! -w "/opt" ]; then | ||
| if [ "$EUID" -ne 0 ]; then | ||
| if [[ ! -w "/opt" ]]; then | ||
| if [[ "$EUID" -ne 0 ]]; then | ||
| print_warn "Root privileges required to create $compose_dir" | ||
| read -rp " Use sudo for directory creation? (Y/n): " use_sudo | ||
| use_sudo="${use_sudo:-y}" | ||
|
|
@@ -220,8 +244,7 @@ deploy_portainer() { | |
| fi | ||
|
|
||
| print_info "Creating directory: $compose_dir" | ||
| $SUDO mkdir -p "$compose_dir" | ||
| if [ $? -ne 0 ]; then | ||
| if ! $SUDO mkdir -p "$compose_dir"; then | ||
| print_error "Failed to create directory." | ||
| return 1 | ||
| fi | ||
|
|
@@ -236,6 +259,11 @@ deploy_portainer() { | |
| return 1 | ||
| fi | ||
|
|
||
| if ! pin_portainer_image "$compose_file"; then | ||
| $SUDO rm -f "$compose_file" | ||
| return 1 | ||
| fi | ||
|
|
||
|
Comment on lines
+262
to
+266
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win Preserve the existing compose file when validation fails. The download overwrites the live compose path, then this failure path deletes it. Stage the download in a temporary file, pin and validate it, and only then atomically replace 🤖 Prompt for AI Agents |
||
| # Validate the downloaded file | ||
| if ! validate_compose_file "$compose_file"; then | ||
| print_error "Downloaded compose file failed validation." | ||
|
|
@@ -247,16 +275,13 @@ deploy_portainer() { | |
| print_info "Starting Portainer containers..." | ||
| echo "" | ||
|
|
||
| cd "$compose_dir" || return 1 | ||
|
|
||
| if $SUDO docker compose -f "$compose_file" up -d; then | ||
| echo "" | ||
| print_success "Portainer deployed successfully!" | ||
| else | ||
| if ! $SUDO docker compose -f "$compose_file" up -d; then | ||
| print_error "Failed to deploy Portainer." | ||
| return 1 | ||
| fi | ||
|
|
||
| echo "" | ||
| print_success "Portainer deployed successfully!" | ||
| return 0 | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: Narehood/Docker-Prep
Length of output: 199
🏁 Script executed:
Repository: Narehood/Docker-Prep
Length of output: 271
Pin
actions/checkoutto a full commit SHA.v4is mutable and can move without a repository change, which weakens supply-chain reproducibility in this security-sensitive workflow. Pin it to34e114876b0b11c390a56381ad16ebd13914f8d5instead.🤖 Prompt for AI Agents