From 291ae5345e4144d49bd4359d5bb036dc3842f60c Mon Sep 17 00:00:00 2001 From: pi Date: Mon, 13 Jul 2026 18:20:44 +0200 Subject: [PATCH] repo: add LICENSE, THIRD_PARTY.md, .dockerignore, hadolint lint, IDEAS backlog Repo/CI hygiene batch (none base-affecting; image contents unchanged): - LICENSE: actual MIT file (repo previously declared MIT only in prose). - THIRD_PARTY.md: notes bundled software + licenses (pi/pi-fork/pi-obsmem/ pi-studio MIT, gosu Apache-2.0, Debian packages under their own terms). - .dockerignore: trims build context to what the Dockerfiles COPY (rootfs/ + entrypoint*.sh); keeps .git/docs/scripts/compose out. Verified it excludes none of the required COPY sources. - lint.yml: new hadolint job (pinned v2.14.0) lints both Dockerfiles; .hadolint.yaml grandfathers deliberate choices (DL3008/DL3016/DL4006/DL3003/ SC2086, mirroring the shellcheck excludes), fails on anything new at warning+. Verified hadolint exit 0 and the repo shell-guard passes with the new job. - IDEAS.md: parks deferred follow-ups (SHA-pin actions, trivy, buildx SBOM/ provenance, Makefile, renovate). - README/DOCKER_HUB License sections now link LICENSE + THIRD_PARTY.md. No tag. --- .dockerignore | 35 +++++++++++++++++++++++ .gitea/workflows/lint.yml | 26 ++++++++++++++++- .hadolint.yaml | 27 ++++++++++++++++++ CHANGELOG.md | 23 +++++++++++++++ DOCKER_HUB.md | 3 +- IDEAS.md | 60 +++++++++++++++++++++++++++++++++++++++ LICENSE | 21 ++++++++++++++ README.md | 5 +++- THIRD_PARTY.md | 46 ++++++++++++++++++++++++++++++ 9 files changed, 243 insertions(+), 3 deletions(-) create mode 100644 .dockerignore create mode 100644 .hadolint.yaml create mode 100644 IDEAS.md create mode 100644 LICENSE create mode 100644 THIRD_PARTY.md diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..35c5469 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,35 @@ +# Keep the Docker build context minimal and prevent stray files (notably +# `.git`) from ever being pulled in by a future broad COPY. Both Dockerfiles +# only COPY `rootfs/` and `entrypoint*.sh`, so everything below is safe to +# exclude from the context. +# +# DO NOT add `rootfs/`, `entrypoint.sh`, `entrypoint-user.sh`, or the +# Dockerfiles here — they are required to build the image. + +# VCS / CI metadata +.git +.gitea +.gitignore +.dockerignore + +# Lint / editor config +.hadolint.yaml +.editorconfig + +# Docs & project meta +README.md +DOCKER_HUB.md +CHANGELOG.md +AGENTS.md +IDEAS.md +LICENSE +THIRD_PARTY.md +docs + +# Local orchestration & examples (compose runs the image; not a build input) +docker-compose.yml +docker-compose.mempalace.yml +.env.example + +# Repo tooling / tests (run from a checkout, not baked into the image) +scripts diff --git a/.gitea/workflows/lint.yml b/.gitea/workflows/lint.yml index 5f4cfaa..69048a8 100644 --- a/.gitea/workflows/lint.yml +++ b/.gitea/workflows/lint.yml @@ -1,4 +1,4 @@ -name: Lint workflows +name: Lint # Durable guard against CI-workflow bugs — most importantly the recurring # "bash-only syntax under the default `sh`/dash shell" footgun that broke @@ -67,3 +67,27 @@ jobs: # ("no project was found"). Globbing the workflow files is the # supported way to lint a non-GitHub layout. run: actionlint -color .gitea/workflows/*.yml + + hadolint: + # Lint the two Dockerfiles that ARE the project (the shell/actions linting + # above never looked at them). Config — ignored rules + failure threshold + # — lives in .hadolint.yaml, which hadolint reads automatically, so a local + # `hadolint Dockerfile.base` reproduces CI exactly. + runs-on: ubuntu-latest + container: + image: catthehacker/ubuntu:act-latest + steps: + - uses: actions/checkout@v4 + + - name: Install hadolint (pinned) + env: + HADOLINT_VERSION: 2.14.0 + run: | + curl -fsSL \ + "https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-Linux-x86_64" \ + -o /usr/local/bin/hadolint + chmod +x /usr/local/bin/hadolint + hadolint --version + + - name: Run hadolint + run: hadolint Dockerfile.base Dockerfile.variant diff --git a/.hadolint.yaml b/.hadolint.yaml new file mode 100644 index 0000000..4066092 --- /dev/null +++ b/.hadolint.yaml @@ -0,0 +1,27 @@ +# hadolint configuration for pi-devbox. +# +# Both Dockerfiles are linted in CI (.gitea/workflows/lint.yml → `hadolint` +# job). hadolint reads this file automatically, so a local +# `hadolint Dockerfile.base` reproduces CI exactly. +# +# The ignores below are DELIBERATE project choices — they mirror the +# philosophy of the shellcheck excludes already applied to `run:` steps +# (SHELLCHECK_OPTS in lint.yml). Anything NOT listed here still fails the +# build at `warning` and above, so new Dockerfile smells are caught going +# forward. +ignored: + - DL3008 # "pin apt versions" — intentionally unpinned: the base tracks + # Debian stable and runs `apt-get upgrade`, so pinning point + # versions would rot and fight security updates. + - DL3016 # "pin npm versions" — pi's version IS pinned, but via the + # PI_VERSION build-arg (CI-resolved from npm), not the npm CLI. + - DL4006 # "set -o pipefail before a pipe" — the piped RUNs are + # download|extract steps with their own retries / `set -e`. + # Switching the global SHELL to bash is a larger, base-affecting + # change — tracked in IDEAS.md. + - DL3003 # "use WORKDIR, not cd" — cosmetic in the few `cd` RUNs here. + - SC2086 # "double-quote to prevent word-splitting" — the same code is + # excluded for shell `run:` steps in lint.yml; splitting is + # intentional in these contexts. + +failure-threshold: warning diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d179e8..2a40d47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,29 @@ Pre-v1.0.0 tags followed the pi npm version (`v{pi_version}[letter]`). overridden per-user (`:set notermguicolors`, or your own init). Base-affecting (`Dockerfile.base` apt package + COPY), rebuilds `base-`. +- **Repository hygiene: `LICENSE`, `THIRD_PARTY.md`, and `.dockerignore`.** The + repo declared MIT only in prose; it now ships an actual `LICENSE` file (MIT, + © Joakim Persson) plus `THIRD_PARTY.md` recording that the published images + bundle third-party software under its own terms (pi, pi-fork, + pi-observational-memory, pi-studio — all MIT; gosu Apache-2.0; Debian packages + under their respective licenses). A new `.dockerignore` trims the build + context to what the Dockerfiles actually `COPY` (`rootfs/` + `entrypoint*.sh`), + keeping `.git`, docs, `scripts/`, and compose files out — cheaper context and + no risk of a future broad `COPY` pulling in `.git`. Not base-affecting (the + base hash covers only `Dockerfile.base` + `rootfs/` + `entrypoint*.sh`); + image contents are byte-identical. + +- **Dockerfile linting (`hadolint`) in CI, plus an `IDEAS.md` backlog.** The + lint workflow already ran actionlint + shellcheck on `run:` steps but never + looked at the two Dockerfiles that are the heart of the project. A new + `hadolint` job (pinned v2.14.0, same download-pin pattern as actionlint) lints + `Dockerfile.base` and `Dockerfile.variant`; `.hadolint.yaml` grandfathers the + deliberate choices (unpinned apt/npm, `cd`-in-`RUN`, `SC2086` — mirroring the + existing shellcheck excludes) and fails on anything new at `warning`+. + `IDEAS.md` parks the vetted-but-unscheduled follow-ups (SHA-pin CI actions, + trivy scanning, buildx SBOM/provenance attestations, a local `Makefile`, + renovate). Repo/CI only — not baked into the image. + ### Changed - **`-studio` images now pin pi-studio to its newest *semver tag* instead of diff --git a/DOCKER_HUB.md b/DOCKER_HUB.md index 495ed12..b68db79 100644 --- a/DOCKER_HUB.md +++ b/DOCKER_HUB.md @@ -156,4 +156,5 @@ Optional volumes for MemPalace (commented out by default — uncomment in `docke ## License -MIT (the image; pi and the bundled tools each carry their own licenses). +MIT (the image; pi and the bundled tools each carry their own licenses). See +`LICENSE` and `THIRD_PARTY.md` in the [source repo](https://gitea.jordbo.se/joakimp/pi-devbox). diff --git a/IDEAS.md b/IDEAS.md new file mode 100644 index 0000000..f34a1d1 --- /dev/null +++ b/IDEAS.md @@ -0,0 +1,60 @@ +# Ideas & backlog + +A living list of potential improvements for pi-devbox that are **not yet +scheduled**. This is intentionally lightweight — a place to park ideas so they +aren't lost between sessions. When an item ships, describe it in +[`CHANGELOG.md`](CHANGELOG.md) and remove it from here. + +Rough effort tags: 🟢 small · 🟡 medium · 🔴 large. Status: `idea` (unvetted) · +`planned` (agreed, not started). + +--- + +## Supply-chain hardening + +- 🟡 `planned` — **Pin CI actions to commit SHAs.** The workflows use floating + major tags (`actions/checkout@v4`, `docker/build-push-action@v7`, + `docker/setup-buildx-action@v4`, `docker/login-action@v3`, + `docker/setup-qemu-action@v3`). This is inconsistent with the project's own + philosophy of SHA-pinning *content* refs (pi, pi-studio, pi-fork, …) to defeat + floating refs. Pin each action to a SHA with a trailing `# vX.Y.Z` comment. + Pairs naturally with the renovate item below to keep the pins fresh. + +- 🟡 `planned` — **Vulnerability scanning in CI.** No CVE scan runs on the + published images today. Add a `trivy image` (or grype) job to + `docker-publish.yml` after `smoke`. Start non-blocking (report only), then + tighten to fail on `HIGH`/`CRITICAL` with an available fix. + +- 🟢🟡 `planned` — **Standardize build provenance → buildx SBOM + attestations.** + The image already carries hand-rolled provenance (OCI labels + + `build-manifest`). `docker/build-push-action` can emit a standard SBOM and + SLSA provenance attestation nearly for free (`provenance: mode=max`, + `sbom: true`). Makes provenance machine-consumable and pairs well with the + trivy item (scan the SBOM). + +## Dockerfile hardening + +- 🟡 `idea` — **Address hadolint DL4006 properly.** Currently ignored in + `.hadolint.yaml`. The clean fix is `SHELL ["/bin/bash", "-o", "pipefail", + "-c"]` so piped `RUN`s fail on the first non-zero stage. This changes the + default `RUN` shell from `sh` to `bash` for all subsequent layers, so it is + base-affecting and needs a careful pass over existing `RUN`s before removing + the ignore. + +## Developer experience + +- 🟢 `idea` — **`Makefile`/`justfile` for local iteration.** Reproducing a CI + build locally means hand-assembling many `--build-arg`s. Thin targets + (`make build-base`, `make build-variant`, `make smoke`, `make lint`) would + make local testing painless and document the canonical invocations. + +- 🟡 `idea` — **Dependency-update automation (renovate).** With CI actions + SHA-pinned (above), a `renovate.json` keeps those pins — plus the pinned tool + versions (`ACTIONLINT_VERSION`, `HADOLINT_VERSION`, gosu, etc.) — current via + automated PRs. Requires a renovate runner against the Gitea instance. + +## Housekeeping + +- 🟢 `idea` — **Registry retention for `base-` tags.** The base-hash + caching scheme accumulates `base-` tags over time. Confirm whether the + registry prunes old ones, and add a retention/cleanup step if not. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7e3c6fb --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Joakim Persson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 9f8ccf9..0f902ae 100644 --- a/README.md +++ b/README.md @@ -783,4 +783,7 @@ The pi coding-agent itself is [@earendil-works/pi-coding-agent](https://www.npmj ## License -MIT +MIT — see [`LICENSE`](LICENSE). This covers the repository's own contents +(Dockerfiles, entrypoint scripts, `rootfs/` seeds, CI, docs). The published +images bundle third-party software under their own licenses; see +[`THIRD_PARTY.md`](THIRD_PARTY.md). diff --git a/THIRD_PARTY.md b/THIRD_PARTY.md new file mode 100644 index 0000000..8ee3ec2 --- /dev/null +++ b/THIRD_PARTY.md @@ -0,0 +1,46 @@ +# Third-party notices + +pi-devbox is distributed under the MIT License (see [`LICENSE`](LICENSE)), which +covers **this repository's own contents** — the Dockerfiles, entrypoint scripts, +`rootfs/` seeds, CI workflows, and docs. + +The **published container images** (`joakimp/pi-devbox:*`) additionally *bundle* +third-party software, each of which remains under its own license. This file is +a good-faith summary; the authoritative sources are the upstream projects and, +for OS packages, the per-package copyright files inside the image at +`/usr/share/doc//copyright`. + +## pi and its extensions (installed in the variant layer) + +| Component | Upstream | License | +| --- | --- | --- | +| pi (`@earendil-works/pi-coding-agent`) | npm | MIT | +| pi-fork | github.com/elpapi42/pi-fork | MIT | +| pi-observational-memory | github.com/elpapi42/pi-observational-memory | MIT | +| pi-studio *(`-studio` variant only)* | github.com/omaclaren/pi-studio | MIT | +| pi-toolkit, pi-extensions, mempalace-toolkit | authored by the maintainer (Joakim Persson) | MIT | + +## Tooling baked into the base image + +| Component | Upstream | License (best effort) | +| --- | --- | --- | +| gosu | github.com/tianon/gosu | Apache-2.0 | +| Node.js | nodejs.org | MIT (bundles components under their own licenses) | +| uv | github.com/astral-sh/uv | Apache-2.0 OR MIT | +| Neovim | neovim.io | Apache-2.0 + Vim license | +| Pandoc | pandoc.org | GPL-2.0-or-later | +| Typst | github.com/typst/typst | Apache-2.0 | +| ripgrep / fd / micro / tealdeer / yq (mikefarah) | respective repos | MIT / Apache-2.0 / Unlicense (varies) | + +## Base OS + +The image is built `FROM` a Debian base and installs packages via `apt`. Debian +and its packages are distributed under their respective licenses (GPL, LGPL, +MIT, BSD, and others). See each package's copyright file in the image under +`/usr/share/doc//copyright`. + +--- + +*Licenses marked "best effort" are widely known but were not each verified at +the exact bundled version; consult the upstream project for authoritative +terms. Corrections welcome.*