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,196 +0,0 @@
1-# Proposal: Integrating Pici with GitHub Actions & `pipe.pico.sh` Remote Debugging
2-
3-## 1. Executive Summary
4-
5-Migrating existing projects away from GitHub Actions to a dedicated self-hosted CI system is difficult due to ecosystem inertia and configuration friction.
6-
7-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.
8-
9----
10-
11-## 2. Core Design Goals
12-
13-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.
14-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.
15-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.
16-4. **Native Docker Compatibility**: Mounts like `$(pwd):/app` work seamlessly in both local and CI environments.
17-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.
18-6. **Security & Secret Scrubbing**: `pici` controls the debug shell environment and scrubs `GITHUB_TOKEN` and repository secrets before spawning interactive shells.
19-
20----
21-
22-## 3. The Custom GitHub Action: `pico-sh/pici-action`
23-
24-We are creating and publishing an official custom action—`pico-sh/pici-action`—that serves as the turnkey entrypoint for GitHub Actions users.
25-
26-### Standard Workflow (`.github/workflows/ci.yml`)
27-
28-With the custom action, adding Pici CI with remote debugging to any repo is a single step:
29-
30-```yaml
31-name: CI
32-on: [push, pull_request]
33-
34-jobs:
35- ci:
36- runs-on: ubuntu-latest
37- steps:
38- - uses: actions/checkout@v4
39-
40- - name: Run CI with Pici
41- uses: picosh/pici-action@v1
42- with:
43- pico_ssh_key: ${{ secrets.PICO_SSH_KEY }}
44-```
45-
46-### Action Configuration & Inputs
47-
48-| Input | Description | Default |
49-| :--- | :--- | :--- |
50-| `pico_ssh_key` | SSH private key registered with pico.sh for authenticated debug relay access. | `""` (optional, required for debug relay) |
51-| `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"` |
52-
53-### What `pico-sh/pici-action` Does Under the Hood
54-1. **Tool Installation**: Installs the static `pici` and pinned `zmx` binaries (with SHA256 checksum verification) to `/usr/local/bin`.
55-2. **Credential Setup**: Writes `pico_ssh_key` to a secure temp keyfile or SSH agent if provided.
56-3. **Environment Propagation**: Passes GitHub Actions run metadata to `pici run`:
57- - `PICI_JOB="${GITHUB_RUN_ID}"`
58- - `PICI_EVENT="git.${GITHUB_EVENT_NAME}"`
59- - `PICI_BRANCH="${GITHUB_REF_NAME}"`
60- - `PICI_COMMIT="${GITHUB_SHA}"`
61-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`).
62-5. **Job Summaries & Artifact Upload**:
63- - `pici` formats the run status table and failed logs into `$GITHUB_STEP_SUMMARY`.
64- - If `upload_artifacts` is enabled, the action uploads `/tmp/pici-artifacts/<repo>/<jobid>/` as a workflow artifact.
65-
66----
67-
68-## 4. Direct CLI Execution (Without the Action)
69-
70-For users who prefer manual step-by-step control or non-GitHub CI environments, `pici run` can be invoked directly:
71-
72-```yaml
73- - name: Run CI
74- run: |
75- pici run --in-place \
76- -e PICI_JOB="$GITHUB_RUN_ID" \
77- -e PICI_EVENT=git.push \
78- -e PICI_BRANCH="$GITHUB_REF_NAME" \
79- -e PICI_COMMIT="$GITHUB_SHA"
80-```
81-
82----
83-
84-## 5. Native Go Debug Bridge (`pipe.pico.sh`)
85-
86-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`:
87-
88-### How it works
89-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.
90-2. **Native SSH Dialing**: `pici` dials `pipe.pico.sh` using the existing `-pk` / `-ck` SSH key infrastructure.
91-3. **PTY Allocation (`creack/pty`)**: Spawns an interactive shell (`bash -i` or `$SHELL`) connected to the bidirectional SSH stream.
92-4. **Attach Instructions & Notifications**: Prints the `ssh -t pipe.pico.sh pipe <topic>` command to stdout and appends it to `$GITHUB_STEP_SUMMARY`.
93-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.
94-6. **Standalone `pici debug`**: `pici debug <repo>/<jobid>` attaches to running or stalled jobs by targeting the deterministic session prefix (`ci.<repo>.<jobid>.`).
95-
96-### Security Advantages
97-- **Environment Scrubbing**: Sensitive CI environment variables (`GITHUB_TOKEN`, `ACTIONS_RUNTIME_TOKEN`, injected secrets) are stripped from the debug shell process environment before launching.
98-- **Host Key Pinning**: The `pipe.pico.sh` host key is verified natively in Go without passing `-o StrictHostKeyChecking=no`.
99-
100----
101-
102-## 6. Implementation & Verification Plan (Test Repository)
103-
104-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.
105-
106-### Step 1: Create the Test Repository Structure
107-
108-```
109-pici-test/
110-├── .github/
111-│ └── workflows/
112-│ ├── ci-action.yml # Tests the custom picosh/pici-action
113-│ └── ci-direct.yml # Tests direct pici binary execution
114-├── src/
115-│ └── main_test.go
116-├── pico.sh # Core CI script with configurable test modes
117-└── README.md
118-```
119-
120-### Step 2: Implement the Configurable `pico.sh`
121-
122-The test script supports environment variables to deterministically simulate success, failure, Docker steps, and hangs:
123-
124-```bash
125-#!/usr/bin/env bash
126-set -euo pipefail
127-
128-JOB_ID="${PICI_JOB:-local}"
129-REPO="${PICI_REPO:-pici-test}"
130-EVENT="${PICI_EVENT:-local}"
131-ZMX_SESSION_PREFIX="${ZMX_SESSION_PREFIX:-local.}"
132-
133-echo "==> Running CI for $REPO (job: $JOB_ID, event: $EVENT)"
134-
135-# 1. Parallel test steps
136-zmx run unit-tests -d bash -c 'echo "Running unit tests..."; sleep 2; echo "Tests passed!"'
137-zmx run lint -d bash -c 'echo "Running linter..."; sleep 1; echo "Lint clean!"'
138-
139-# 2. Simulated failure scenario (when TEST_FAILURE=1)
140-if [ "${TEST_FAILURE:-0}" = "1" ]; then
141- zmx run failing-step -d bash -c 'echo "Simulating fatal compilation error..."; sleep 2; exit 42'
142-fi
143-
144-# 3. Simulated hang scenario (when TEST_HANG=1)
145-if [ "${TEST_HANG:-0}" = "1" ]; then
146- zmx run hung-test -d bash -c 'echo "Simulating hung test process..."; sleep 3600'
147-fi
148-
149-# 4. Docker container step
150-zmx run docker-step -d docker run --rm alpine:latest sh -c "echo 'Docker step executed inside alpine container'"
151-
152-# 5. Wait for all steps
153-zmx wait "*"
154-
155-printf "\x1b[32mAll test steps succeeded!\x1b[0m\n"
156-```
157-
158-### Step 3: Configure GitHub Actions Workflows
159-
160-#### Test Workflow 1: Using `picosh/pici-action` (`.github/workflows/ci-action.yml`)
161-
162-```yaml
163-name: Pici Action Validation
164-on:
165- push:
166- workflow_dispatch:
167- inputs:
168- test_failure:
169- description: "Simulate step failure (exit 42)"
170- type: boolean
171- default: false
172-
173-jobs:
174- test-ci:
175- runs-on: ubuntu-latest
176- steps:
177- - uses: actions/checkout@v4
178-
179- - name: Run Pici CI
180- uses: picosh/pici-action@main
181- with:
182- pico_ssh_key: ${{ secrets.PICO_SSH_KEY }}
183- debug_on_fail: "true"
184- env:
185- TEST_FAILURE: ${{ github.event.inputs.test_failure && '1' || '0' }}
186-```
187-
188-### Step 4: Verification Matrix & Acceptance Criteria
189-
190-| Test Scenario | Trigger | Expected GHA Behavior | Acceptance Criteria |
191-| :--- | :--- | :--- | :--- |
192-| **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. |
193-| **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). |
194-| **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`. |
195-| **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`. |
196-| **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). |