Commit 50d7d59
Eric Bower
·
2026-08-15 21:00:22 -0400 EDT
parent 50e9dba
chore: rm proposal
1 files changed,
+0,
-196
+0,
-196
1@@ -1,196 +0,0 @@
2-# Proposal: Integrating Pici with GitHub Actions & `pipe.pico.sh` Remote Debugging
3-
4-## 1. Executive Summary
5-
6-Migrating existing projects away from GitHub Actions to a dedicated self-hosted CI system is difficult due to ecosystem inertia and configuration friction.
7-
8-This proposal outlines a strategy to provide an **official custom GitHub Action (`pico-sh/pici-action`)** powered by `pici run`. Developers write standard, parallel bash workflows (`pico.sh`) using `zmx`, execute them with 1:1 parity on both local workstations and GitHub Actions runners, and gain **live, interactive terminal debugging on failure** powered by native `pipe.pico.sh` bridging in Go.
9-
10----
11-
12-## 2. Core Design Goals
13-
14-1. **1-Step GitHub Action Experience**: A custom composite action (`pico-sh/pici-action@v1`) that installs `pici` + `zmx`, configures SSH keys, executes the workflow in-place, and uploads artifacts with zero boilerplate.
15-2. **1:1 Local & Remote Parity**: `pici run` provides identical execution semantics across environments: metadata environment variable injection (`PICI_JOB`, `PICI_REPO`, `PICI_BRANCH`, `PICI_COMMIT`), `pico.sh` execution via `zmx`, live progress streaming, artifact rendering, and exit code propagation.
16-3. **Explicit Workspace Semantics**: By default, `pici run` rsyncs to an isolated `/tmp` workspace to keep local working trees clean. In CI environments where the runner is already an ephemeral container/VM, an explicit `--in-place` flag instructs `pici run` to execute directly without rsyncing.
17-4. **Native Docker Compatibility**: Mounts like `$(pwd):/app` work seamlessly in both local and CI environments.
18-5. **Native Go Failure Hook (`pici debug`)**: When a job fails, `pici` directly opens a secure, authenticated PTY bridge to `pipe.pico.sh` in Go, avoiding brittle bash FIFOs or background SSH wrappers.
19-6. **Security & Secret Scrubbing**: `pici` controls the debug shell environment and scrubs `GITHUB_TOKEN` and repository secrets before spawning interactive shells.
20-
21----
22-
23-## 3. The Custom GitHub Action: `pico-sh/pici-action`
24-
25-We are creating and publishing an official custom action—`pico-sh/pici-action`—that serves as the turnkey entrypoint for GitHub Actions users.
26-
27-### Standard Workflow (`.github/workflows/ci.yml`)
28-
29-With the custom action, adding Pici CI with remote debugging to any repo is a single step:
30-
31-```yaml
32-name: CI
33-on: [push, pull_request]
34-
35-jobs:
36- ci:
37- runs-on: ubuntu-latest
38- steps:
39- - uses: actions/checkout@v4
40-
41- - name: Run CI with Pici
42- uses: picosh/pici-action@v1
43- with:
44- pico_ssh_key: ${{ secrets.PICO_SSH_KEY }}
45-```
46-
47-### Action Configuration & Inputs
48-
49-| Input | Description | Default |
50-| :--- | :--- | :--- |
51-| `pico_ssh_key` | SSH private key registered with pico.sh for authenticated debug relay access. | `""` (optional, required for debug relay) |
52-| `debug_on_fail` | Automatically open an interactive `pipe.pico.sh` debug bridge if a job fails. If omitted or `auto`, automatically enables when re-running with GitHub debug logging (`RUNNER_DEBUG=1`). | `"auto"` |
53-
54-### What `pico-sh/pici-action` Does Under the Hood
55-1. **Tool Installation**: Installs the static `pici` and pinned `zmx` binaries (with SHA256 checksum verification) to `/usr/local/bin`.
56-2. **Credential Setup**: Writes `pico_ssh_key` to a secure temp keyfile or SSH agent if provided.
57-3. **Environment Propagation**: Passes GitHub Actions run metadata to `pici run`:
58- - `PICI_JOB="${GITHUB_RUN_ID}"`
59- - `PICI_EVENT="git.${GITHUB_EVENT_NAME}"`
60- - `PICI_BRANCH="${GITHUB_REF_NAME}"`
61- - `PICI_COMMIT="${GITHUB_SHA}"`
62-4. **Execution (`pici run`)**: Invokes `pici run --in-place` (enabling `--debug-on-fail` if `debug_on_fail: true` or if GitHub's native debug re-run is active via `RUNNER_DEBUG=1`).
63-5. **Job Summaries & Artifact Upload**:
64- - `pici` formats the run status table and failed logs into `$GITHUB_STEP_SUMMARY`.
65- - If `upload_artifacts` is enabled, the action uploads `/tmp/pici-artifacts/<repo>/<jobid>/` as a workflow artifact.
66-
67----
68-
69-## 4. Direct CLI Execution (Without the Action)
70-
71-For users who prefer manual step-by-step control or non-GitHub CI environments, `pici run` can be invoked directly:
72-
73-```yaml
74- - name: Run CI
75- run: |
76- pici run --in-place \
77- -e PICI_JOB="$GITHUB_RUN_ID" \
78- -e PICI_EVENT=git.push \
79- -e PICI_BRANCH="$GITHUB_REF_NAME" \
80- -e PICI_COMMIT="$GITHUB_SHA"
81-```
82-
83----
84-
85-## 5. Native Go Debug Bridge (`pipe.pico.sh`)
86-
87-Rather than relying on bash scripts with named FIFOs (`mkfifo`) and background `ssh -N` commands, the relay bridge is implemented directly in Go inside `pici`:
88-
89-### How it works
90-1. **Hook into Failure Path**: When `resolveJobExitCode()` detects a non-zero exit in `waitAndReport()` and debug mode is enabled (via `--debug-on-fail`, `-e PICI_DEBUG=1`, or GitHub Actions' standard `RUNNER_DEBUG=1`), `pici` initializes the debug session.
91-2. **Native SSH Dialing**: `pici` dials `pipe.pico.sh` using the existing `-pk` / `-ck` SSH key infrastructure.
92-3. **PTY Allocation (`creack/pty`)**: Spawns an interactive shell (`bash -i` or `$SHELL`) connected to the bidirectional SSH stream.
93-4. **Attach Instructions & Notifications**: Prints the `ssh -t pipe.pico.sh pipe <topic>` command to stdout and appends it to `$GITHUB_STEP_SUMMARY`.
94-5. **Idle Timeout & Clean Exit**: Waits for a connection with an idle timeout (e.g., 15 minutes). Once closed or timed out, `pici` terminates and exits with the original non-zero job exit code.
95-6. **Standalone `pici debug`**: `pici debug <repo>/<jobid>` attaches to running or stalled jobs by targeting the deterministic session prefix (`ci.<repo>.<jobid>.`).
96-
97-### Security Advantages
98-- **Environment Scrubbing**: Sensitive CI environment variables (`GITHUB_TOKEN`, `ACTIONS_RUNTIME_TOKEN`, injected secrets) are stripped from the debug shell process environment before launching.
99-- **Host Key Pinning**: The `pipe.pico.sh` host key is verified natively in Go without passing `-o StrictHostKeyChecking=no`.
100-
101----
102-
103-## 6. Implementation & Verification Plan (Test Repository)
104-
105-To validate the complete flow end-to-end before public release, we will use a dedicated test repository (e.g., `picosh/pici-test`) to confirm local parity, GitHub Actions execution, and interactive failure recovery.
106-
107-### Step 1: Create the Test Repository Structure
108-
109-```
110-pici-test/
111-├── .github/
112-│ └── workflows/
113-│ ├── ci-action.yml # Tests the custom picosh/pici-action
114-│ └── ci-direct.yml # Tests direct pici binary execution
115-├── src/
116-│ └── main_test.go
117-├── pico.sh # Core CI script with configurable test modes
118-└── README.md
119-```
120-
121-### Step 2: Implement the Configurable `pico.sh`
122-
123-The test script supports environment variables to deterministically simulate success, failure, Docker steps, and hangs:
124-
125-```bash
126-#!/usr/bin/env bash
127-set -euo pipefail
128-
129-JOB_ID="${PICI_JOB:-local}"
130-REPO="${PICI_REPO:-pici-test}"
131-EVENT="${PICI_EVENT:-local}"
132-ZMX_SESSION_PREFIX="${ZMX_SESSION_PREFIX:-local.}"
133-
134-echo "==> Running CI for $REPO (job: $JOB_ID, event: $EVENT)"
135-
136-# 1. Parallel test steps
137-zmx run unit-tests -d bash -c 'echo "Running unit tests..."; sleep 2; echo "Tests passed!"'
138-zmx run lint -d bash -c 'echo "Running linter..."; sleep 1; echo "Lint clean!"'
139-
140-# 2. Simulated failure scenario (when TEST_FAILURE=1)
141-if [ "${TEST_FAILURE:-0}" = "1" ]; then
142- zmx run failing-step -d bash -c 'echo "Simulating fatal compilation error..."; sleep 2; exit 42'
143-fi
144-
145-# 3. Simulated hang scenario (when TEST_HANG=1)
146-if [ "${TEST_HANG:-0}" = "1" ]; then
147- zmx run hung-test -d bash -c 'echo "Simulating hung test process..."; sleep 3600'
148-fi
149-
150-# 4. Docker container step
151-zmx run docker-step -d docker run --rm alpine:latest sh -c "echo 'Docker step executed inside alpine container'"
152-
153-# 5. Wait for all steps
154-zmx wait "*"
155-
156-printf "\x1b[32mAll test steps succeeded!\x1b[0m\n"
157-```
158-
159-### Step 3: Configure GitHub Actions Workflows
160-
161-#### Test Workflow 1: Using `picosh/pici-action` (`.github/workflows/ci-action.yml`)
162-
163-```yaml
164-name: Pici Action Validation
165-on:
166- push:
167- workflow_dispatch:
168- inputs:
169- test_failure:
170- description: "Simulate step failure (exit 42)"
171- type: boolean
172- default: false
173-
174-jobs:
175- test-ci:
176- runs-on: ubuntu-latest
177- steps:
178- - uses: actions/checkout@v4
179-
180- - name: Run Pici CI
181- uses: picosh/pici-action@main
182- with:
183- pico_ssh_key: ${{ secrets.PICO_SSH_KEY }}
184- debug_on_fail: "true"
185- env:
186- TEST_FAILURE: ${{ github.event.inputs.test_failure && '1' || '0' }}
187-```
188-
189-### Step 4: Verification Matrix & Acceptance Criteria
190-
191-| Test Scenario | Trigger | Expected GHA Behavior | Acceptance Criteria |
192-| :--- | :--- | :--- | :--- |
193-| **1. Happy Path** | Push commit with `TEST_FAILURE=0` | All `zmx` sessions pass. | • Workflow exits with `0` (green).<br>• GHA Step Summary displays full table with durations.<br>• HTML report uploaded as workflow artifact. |
194-| **2. Failure & Remote Attach** | Dispatch workflow with `test_failure=true` | `failing-step` exits `42`. | • `waitAndReport` catches exit `42`.<br>• Relay bridge opens on `pipe.pico.sh`.<br>• `ssh -t pipe.pico.sh pipe <topic>` printed to logs and step summary.<br>• Connecting via terminal drops into interactive debug shell with active `zmx` sessions.<br>• Exiting debug shell ends GHA job with code `42` (red). |
195-| **3. Secret Scrubbing Audit** | During interactive debug session | Inspect environment variables inside attached shell. | • `GITHUB_TOKEN`, `ACTIONS_RUNTIME_TOKEN`, and `PICO_SSH_KEY` are absent from `env`. |
196-| **4. Docker Step Execution** | Standard run | Alpine container runs via `docker run --rm`. | • Docker mounts `$(pwd)` correctly in-place.<br>• Container logs captured in `zmx history docker-step`. |
197-| **5. Idle Timeout Cleanup** | Failure triggered without developer attaching | Wait for configured idle timeout (e.g. 15m). | • Bridge cleanly closes upon timeout.<br>• GHA runner exits with the original step failure code (does not hang indefinitely). |