diff --git a/README.md b/README.md index eb28779..5da3add 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,43 @@ Ollama is never installed inside the container (Constitution I). When the endpoint is empty or unreachable, the container starts normally and Dewey falls back to keyword search. +### Factory URLs + +Eclipse Che supports one-click workspace creation via factory URLs. +Navigate to the URL and Che creates a workspace automatically. + +By default, Che uses `devfile.yaml` at the repository root: + +``` +https:///#https://github.com/unbound-force/containerfile +``` + +To use the dynamic devfile (UDI + postStart), append the devfile path: + +``` +https:///#https://github.com/unbound-force/containerfile?devfilePath=devfile-dynamic.yaml +``` + +Replace `` with your Eclipse Che instance hostname +(e.g., `che.example.com`). + +### Red Hat Dev Spaces + +Expected to be compatible with Red Hat OpenShift Dev Spaces. Not yet +tested in a Dev Spaces environment. + +Known differences from open-source Eclipse Che: + +- **Per-user namespaces** — Dev Spaces creates a Kubernetes namespace + per user automatically +- **OpenShift OAuth** — SSO via OpenShift identity provider instead of + standalone Keycloak +- **Image registry** — container images must come from a trusted + registry (quay.io is fine) + +For more information, see the +[Red Hat Dev Spaces documentation](https://developers.redhat.com/products/openshift-dev-spaces/overview). + ## Security Model These constraints are non-negotiable: diff --git a/devfile-dynamic.yaml b/devfile-dynamic.yaml index e38e1ef..a2303a8 100644 --- a/devfile-dynamic.yaml +++ b/devfile-dynamic.yaml @@ -52,16 +52,25 @@ commands: exec: component: dev-container commandLine: | - # Install UF tools via go install + npm - if [ -f /projects/scripts/install-uf-tools.sh ]; then - bash /projects/scripts/install-uf-tools.sh - else - echo "install-uf-tools.sh not found in /projects/scripts/" - echo "Clone the containerfile repo or provide the script." - exit 1 - fi + # Downloads install script from containerfile repo — works with any cloned project. + # Uses main branch (not SHA-pinned) so workspaces always get the latest tools. + # Retry up to 3 times for transient CDN failures (rate limiting, 503s). + for attempt in 1 2 3; do + if curl -fsSL --max-time 60 https://raw.githubusercontent.com/unbound-force/containerfile/main/scripts/install-uf-tools.sh | bash; then + break + fi + if [ "$attempt" -eq 3 ]; then + echo "WARNING: UF tools installation failed after 3 attempts." >&2 + echo "Check network access to raw.githubusercontent.com" >&2 + break + fi + echo "Install attempt $attempt failed, retrying in 5s ..." + sleep 5 + done # Install OpenCode via official installer - curl -fsSL https://opencode.ai/install | bash + if ! curl -fsSL --max-time 60 https://opencode.ai/install | bash; then + echo "WARNING: OpenCode installation failed. Check network access to opencode.ai" >&2 + fi workingDir: /projects - id: start-server diff --git a/openspec/changes/cde-docs/.openspec.yaml b/openspec/changes/cde-docs/.openspec.yaml new file mode 100644 index 0000000..057956f --- /dev/null +++ b/openspec/changes/cde-docs/.openspec.yaml @@ -0,0 +1,2 @@ +schema: unbound-force +created: 2026-04-13 diff --git a/openspec/changes/cde-docs/design.md b/openspec/changes/cde-docs/design.md new file mode 100644 index 0000000..3caf1fe --- /dev/null +++ b/openspec/changes/cde-docs/design.md @@ -0,0 +1,67 @@ +## Context + +The dynamic devfile's `install-tools` command references a local script +at `/projects/scripts/install-uf-tools.sh` which fails when the cloned +project isn't the containerfile repo. The README lacks factory URL +documentation and Red Hat Dev Spaces notes. + +See proposal.md for full motivation and constitution alignment. + +## Goals / Non-Goals + +### Goals +- Make `devfile-dynamic.yaml` work with any cloned project +- Document factory URL patterns for one-click workspace creation +- Document Red Hat Dev Spaces compatibility (honestly — tested or not) + +### Non-Goals +- Modifying `devfile.yaml` (custom image variant already works) +- Changing the install script itself (`scripts/install-uf-tools.sh`) +- Adding credential injection documentation (tracked in Issue #4) +- Adding devfile schema validation to CI + +## Decisions + +### D1: Curl from GitHub raw URL instead of local script + +**Decision**: Replace the local file reference with: +```bash +curl -fsSL https://raw.githubusercontent.com/unbound-force/containerfile/main/scripts/install-uf-tools.sh | bash +``` + +**Rationale**: This is the simplest approach — no external tooling needed, +same pattern already used for OpenCode installation (`curl | bash`). +The URL points to the `main` branch so it always gets the latest script. +If the repo is private, the URL won't work — but this repo is public. + +**Alternatives rejected**: +- Inline the script in the devfile: bloats the YAML, duplicates logic, + maintenance burden +- Download from a release artifact: adds versioning complexity for a + script that should always be latest + +### D2: Factory URL documentation scope + +**Decision**: Document the factory URL pattern with examples for both +`devfile.yaml` (default) and `devfile-dynamic.yaml` (explicit path). + +**Rationale**: Che uses `devfile.yaml` at repo root by default. To use +`devfile-dynamic.yaml`, the factory URL needs `?devfilePath=devfile-dynamic.yaml`. +Both patterns should be documented. + +### D3: Dev Spaces honesty policy + +**Decision**: Document Dev Spaces as "expected to be compatible" with +known differences called out, but do not claim "tested" unless actually +verified in a Dev Spaces instance. + +**Rationale**: Constitution IV (Executable Truth) requires documentation +to be honest. We haven't tested in Dev Spaces, so we say so. + +## Risks / Trade-offs + +| Risk | Impact | Mitigation | +|------|--------|------------| +| GitHub raw URL unavailable (rate limiting, outage) | Medium — postStart fails | Devfile error message tells user what to check | +| Script changes on main break existing workspaces | Low — script is stable | Version pinning via commit SHA available if needed | +| Dev Spaces has undocumented incompatibilities | Low | Honest documentation; users can file issues | diff --git a/openspec/changes/cde-docs/proposal.md b/openspec/changes/cde-docs/proposal.md new file mode 100644 index 0000000..68d4ad1 --- /dev/null +++ b/openspec/changes/cde-docs/proposal.md @@ -0,0 +1,88 @@ +## Why + +The CDE devfiles and documentation have three gaps: + +1. **Dynamic devfile postStart fails for non-containerfile repos** — + `devfile-dynamic.yaml` references `/projects/scripts/install-uf-tools.sh` + which only exists if the containerfile repo itself is cloned. If an + engineer clones their own project (e.g., `unbound-force/gaze`), the + postStart fails because the script isn't there. + +2. **No factory URL documentation** — Eclipse Che supports one-click + workspace creation via factory URLs + (`https://che.example.com/#https://github.com/...`), but this isn't + documented. Engineers don't know they can create a workspace directly + from a GitHub URL. + +3. **No Red Hat Dev Spaces notes** — The devfiles should work with + Red Hat OpenShift Dev Spaces (enterprise Che), but compatibility + is undocumented and known differences aren't called out. + +Ref: [Issue #5](https://github.com/unbound-force/containerfile/issues/5) + +## What Changes + +### devfile-dynamic.yaml + +Replace the local script reference with a curl download from the +containerfile repo's main branch on GitHub. This removes the +dependency on the containerfile repo being the cloned project. + +### README.md + +- Add factory URL documentation with patterns and examples +- Add Red Hat Dev Spaces compatibility notes + +## Capabilities + +### New Capabilities +- `factory-url`: One-click workspace creation via Che factory URL documented +- `remote-install`: Dynamic devfile downloads install script from GitHub (no local dependency) + +### Modified Capabilities +- `install-tools` (devfile-dynamic.yaml): Changes from local file reference to curl-from-GitHub download + +### Removed Capabilities +- None + +## Impact + +- **devfile-dynamic.yaml**: `install-tools` command rewritten to use curl +- **README.md**: New "Factory URLs" and "Red Hat Dev Spaces" sections +- **No Containerfile changes**: The install script itself is unchanged +- **No CI changes**: Devfile modifications don't affect container image builds + +## Constitution Alignment + +Assessed against the containerfile project constitution (v1.0.0). + +### I. Composability First + +**Assessment**: PASS + +The curl-from-GitHub approach improves composability: the dynamic +devfile no longer requires the containerfile repo to be the cloned +project. Any project can use `devfile-dynamic.yaml` by copying it +into their repo — the install script is fetched at runtime. + +### II. Security Through Isolation + +**Assessment**: N/A + +No security model changes. The curl-from-GitHub pattern has the +same risk profile as the existing OpenCode curl installer (already +mitigated by container isolation per Constitution II). + +### III. Reproducible Builds + +**Assessment**: N/A + +No Containerfile or CI changes. + +### IV. Executable Truth + +**Assessment**: PASS + +README documentation will be updated to match the new devfile +behavior. Factory URL patterns will be verified. Dev Spaces +compatibility will be documented honestly (tested vs untested). diff --git a/openspec/changes/cde-docs/specs/cde-docs.md b/openspec/changes/cde-docs/specs/cde-docs.md new file mode 100644 index 0000000..a73d45a --- /dev/null +++ b/openspec/changes/cde-docs/specs/cde-docs.md @@ -0,0 +1,60 @@ +## ADDED Requirements + +### Requirement: Factory URL Documentation + +README.md MUST document Eclipse Che factory URL patterns for one-click +workspace creation, including: +- Default pattern (`https://che.example.com/#`) +- Explicit devfile path for the dynamic variant +- At least one concrete example URL + +#### Scenario: Engineer creates workspace via factory URL +- **GIVEN** an engineer with access to an Eclipse Che instance +- **WHEN** they navigate to `https://che.example.com/#https://github.com/unbound-force/containerfile` +- **THEN** Che creates a workspace using `devfile.yaml` from the repo root + +#### Scenario: Engineer uses dynamic devfile via factory URL +- **GIVEN** an engineer who wants the UDI-based dynamic devfile +- **WHEN** they append `?devfilePath=devfile-dynamic.yaml` to the factory URL +- **THEN** Che creates a workspace using `devfile-dynamic.yaml` instead + +### Requirement: Red Hat Dev Spaces Documentation + +README.md MUST include a "Red Hat Dev Spaces" section noting: +- Expected compatibility status (tested or untested — be honest) +- Known differences from open-source Eclipse Che +- Link to Dev Spaces documentation + +#### Scenario: Engineer looks for Dev Spaces guidance +- **GIVEN** an engineer using Red Hat OpenShift Dev Spaces +- **WHEN** they read the README +- **THEN** they find guidance on compatibility and any known differences + +## MODIFIED Requirements + +### Requirement: Dynamic Devfile Install Script + +The `install-tools` command in `devfile-dynamic.yaml` MUST download +`install-uf-tools.sh` from the containerfile repo's GitHub raw URL +instead of referencing a local file path. The download MUST use +`curl -fsSL` with the `main` branch URL. + +Previously: The command referenced `/projects/scripts/install-uf-tools.sh` +which only exists when the containerfile repo is the cloned project. + +#### Scenario: Dynamic devfile with a non-containerfile project +- **GIVEN** an engineer who clones `unbound-force/gaze` into a Che workspace + using `devfile-dynamic.yaml` +- **WHEN** the postStart event runs `install-tools` +- **THEN** the script is downloaded from GitHub and tools are installed + successfully + +#### Scenario: GitHub raw URL is unavailable +- **GIVEN** a workspace where `raw.githubusercontent.com` is unreachable +- **WHEN** the postStart event runs `install-tools` +- **THEN** the curl command fails with a clear error (exit 1) and the + workspace starts without UF tools installed + +## REMOVED Requirements + +None. diff --git a/openspec/changes/cde-docs/tasks.md b/openspec/changes/cde-docs/tasks.md new file mode 100644 index 0000000..dce01e4 --- /dev/null +++ b/openspec/changes/cde-docs/tasks.md @@ -0,0 +1,25 @@ +## 1. Fix Dynamic Devfile Install Script + +- [x] 1.1 Replace local script reference in `devfile-dynamic.yaml` `install-tools` command with `curl -fsSL https://raw.githubusercontent.com/unbound-force/containerfile/main/scripts/install-uf-tools.sh | bash` +- [x] 1.2 Keep the OpenCode curl installer line unchanged (already uses curl) +- [x] 1.3 Add a comment in the devfile explaining the GitHub raw URL approach + +## 2. Add Factory URL Documentation + +- [x] 2.1 Add "Factory URLs" section to README.md under Model C (CDE) documentation +- [x] 2.2 Include default pattern: `https:///#https://github.com/unbound-force/containerfile` +- [x] 2.3 Include dynamic devfile pattern: append `?devfilePath=devfile-dynamic.yaml` +- [x] 2.4 Note that Che uses `devfile.yaml` at repo root by default + +## 3. Add Red Hat Dev Spaces Notes + +- [x] 3.1 Add "Red Hat Dev Spaces" section to README.md +- [x] 3.2 State compatibility status honestly (expected compatible, not yet tested in Dev Spaces) +- [x] 3.3 Note known differences: per-user namespaces, OpenShift OAuth, image registry requirements +- [x] 3.4 Link to Dev Spaces documentation + +## 4. Verification + +- [x] 4.1 Validate `devfile-dynamic.yaml` parses as valid YAML +- [x] 4.2 Verify the GitHub raw URL resolves (curl exits 0): `curl -fsSL -o /dev/null https://raw.githubusercontent.com/unbound-force/containerfile/main/scripts/install-uf-tools.sh` +- [x] 4.3 Constitution check: Composability (no local dependency), Executable Truth (README matches devfile, honesty about Dev Spaces)