diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c41a163 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,28 @@ +# ci.yml - run the fast contributor contract without publishing or heavy images + +name: CI + +on: + pull_request: + branches: + - main + push: + branches: + - main + +permissions: + contents: read + +jobs: + check: + name: Check + runs-on: ubuntu-latest + steps: + - name: Check out source + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Install Task + uses: go-task/setup-task@01a4adf9db2d14c1de7a560f09170b6e0df736aa # v2.1.0 + with: + version: 3.52.0 + - name: Run contributor checks + run: task check diff --git a/.oc_local/rules/software-tests.md b/.oc_local/rules/software-tests.md index e548eb3..7b15c48 100644 --- a/.oc_local/rules/software-tests.md +++ b/.oc_local/rules/software-tests.md @@ -2,11 +2,19 @@ Use this rule when making code, script, or workflow changes in this repository. -## Full Suite Default +## Normal Check -- Run the complete `task tests-run` suite before handing off changes. -- Targeted tests are still useful while iterating, but they do not replace the - final full-suite attempt. +- Run `task check` as the normal deterministic verification before handing off + changes. It covers shell syntax and focused source-to-release contracts + without Docker, QEMU, browser, or Dev Containers builds. +- Keep the focused release fixture in a cleanup-trapped OS temporary directory + and copy only its explicit source inputs. `task check` must not create + `.test-tmp/` or copy ignored workspace state, caches, profiles, or logs. +- Run the complete `task tests-run` suite when changes affect the image, Dev + Containers lifecycle, Docker/Compose behavior, QEMU, browser runtime, or + another integration contract covered only by that suite. +- Targeted tests are still useful while iterating, but they do not replace a + relevant final `task check` or broad-suite attempt. - Do not run `docker system prune`, `docker builder prune`, or other Docker cleanup commands automatically before tests. If Docker storage is too tight, stop and ask for approval before pruning cache, images, containers, or volumes. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..0e35394 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,86 @@ +# Contributing To The Devcontainer Kit + +Contributions improve the shared development environment used by Codegeist +repositories. Start with a GitHub Issue when proposing behavior, toolchain, or +workflow changes, and keep pull requests focused on one reviewable outcome. + +## Repository Ownership + +This repository owns the generic VS Code Dev Containers runtime, its image +toolchain, host-side initialization, shared runtime scripts, release assembly, +tests, and kit-specific documentation. + +The `main` branch is the canonical source and contribution target. The +`release` branch is generated from reviewed source by `scripts/release-build.sh` +and contains only the runtime files consumed at `.devcontainer/`. Do not use a +generated `release` checkout, or a consuming repository's `.devcontainer/` +submodule checkout, as an implementation target. + +## Contribution Workflow + +1. Check the repository's [Issues](https://github.com/codegeist-ai/codegeist-devcontainer-kit/issues) + and [roadmap listing](https://github.com/users/codegeist-ai/projects/1) before + starting overlapping work. +2. Link the Issue to a local task under `docs/tasks/` when the work needs a + resumable specification. Follow the [task guide](docs/tasks/README.md). +3. Make the smallest source change on a branch based on `main`. +4. Run the normal deterministic check: + + ```bash + task check + ``` + +5. Run `task tests-run` when changing the image, Dev Containers lifecycle, + Docker/Compose behavior, QEMU, browser runtime, or another contract covered + only by the broad integration suite. +6. Open a pull request that links the public Issue and local task, explains the + source and release impact, and records the verification performed. + +`task check` validates shell syntax and focused source-to-release contracts. It +is non-interactive, does not build the image or start Docker, QEMU, Dev +Containers, or browsers, and does not publish or modify this repository's Git +history. Its focused release fixture copies only required source inputs into a +cleanup-trapped OS temporary directory, so the check leaves no repo-local test +directory, cache, log, or copied local state behind. + +## Extension Boundaries + +Keep shared, repository-agnostic runtime behavior in this source repository. +Consuming repositories should use `.codegeist/.local.env`, +`.codegeist/compose.local.yml`, and `.codegeist/Dockerfile` for documented +runtime extensions instead of editing `.devcontainer/`. Project-specific +OpenCode behavior belongs in the consuming repository's `.oc_local/` overlay, +not in its `.opencode/` or `.devcontainer/` submodule. + +Do not edit this source repository's nested `.devcontainer/` or `.opencode/` +submodules as part of ordinary kit work. + +## Release Publication + +Release publication is maintainer-only. Contributors should not run the +release-publishing workflow or push the generated `release` branch. Maintainers +publish only from clean, reviewed `main` after the full release verification +gate documented in `README.md` has passed. + +## Shared Policies + +Codegeist's account-wide policies apply here and are maintained centrally: + +The visible [Codegeist personal account profile](https://github.com/codegeist-ai) +is sourced from +[`codegeist-ai/codegeist-ai`](https://github.com/codegeist-ai/codegeist-ai). +The separate [`codegeist-ai/.github`](https://github.com/codegeist-ai/.github) +repository remains the source for shared community defaults used here and in +other Codegeist repositories. + +- [Code of Conduct](https://github.com/codegeist-ai/.github/blob/main/CODE_OF_CONDUCT.md) +- [Security Policy](https://github.com/codegeist-ai/.github/blob/main/SECURITY.md) +- [Support Policy](https://github.com/codegeist-ai/.github/blob/main/SUPPORT.md) + +Do not report vulnerabilities in a public Issue; follow the shared Security +Policy. + +## License + +Contributions are provided under the repository's +[Zero-Clause BSD (`0BSD`) license](LICENSE). diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9116b9e --- /dev/null +++ b/LICENSE @@ -0,0 +1,7 @@ +BSD Zero Clause License + +Copyright (C) 2026 Codegeist contributors + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/README.md b/README.md index 40137ed..91f0eef 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,9 @@ Containers workflow with the current Codegeist/planner development toolchain. This repository is a reusable devcontainer kit that can be added to other repositories at `.devcontainer/`, either as a Git subtree or as a Git submodule. +The `main` branch is the canonical source and contribution target. The generated +`release` branch is the runtime-only tree intended for consuming +`.devcontainer/` submodules and is not an implementation target. The source `Dockerfile.base` intentionally carries the full Codegeist/planner-style toolchain, including Docker CE, Node 24, VS Code, GitHub CLI, Maven, GraalVM, JBang, Hugo, Nix, PowerShell through `pwsh`, Task @@ -17,6 +20,17 @@ security scan tools, password-store tooling through `pass`, and related CLI tools. The release build publishes this file as `.devcontainer/Dockerfile` for consuming repositories. +Project work is tracked through +[GitHub Issues](https://github.com/codegeist-ai/codegeist-devcontainer-kit/issues), +the [Codegeist roadmap listing](https://github.com/users/codegeist-ai/projects/1), +and resumable local specifications described in the +[task guide](docs/tasks/README.md). See [CONTRIBUTING.md](CONTRIBUTING.md) for the +source workflow and extension boundaries. Codegeist's shared +[Code of Conduct](https://github.com/codegeist-ai/.github/blob/main/CODE_OF_CONDUCT.md), +[Security Policy](https://github.com/codegeist-ai/.github/blob/main/SECURITY.md), +and [Support Policy](https://github.com/codegeist-ai/.github/blob/main/SUPPORT.md) +apply to this repository. + The consuming project should use the standard VS Code flow: 1. Clone the consuming repository. @@ -373,7 +387,22 @@ If the repository was already cloned without submodules, initialize them later: git submodule update --init --recursive ``` -Run the local test suite from this repository root: +Run the normal fast, deterministic contributor check from this repository root: + +```bash +task check +``` + +This validates shell syntax and the focused source-to-release contract without +building the image, starting Docker, QEMU, Dev Containers, or browsers, +publishing a release, or modifying this repository's Git history. The release +fixture uses a bounded source input list under a cleanup-trapped OS temporary +directory and leaves no `.test-tmp`, cache, log, or copied local state in the +source checkout. + +Run the broad local test suite when changing image contents, Dev Containers +lifecycle behavior, Docker/Compose integration, QEMU, browser runtime, or another +contract covered only by integration tests: ```bash task tests-run @@ -431,6 +460,7 @@ The release branch tree contains only: .oc_local.opencode.json.example Dockerfile Dockerfile.example +LICENSE README.md compose.local.yml.example devcontainer.json @@ -443,7 +473,8 @@ scripts/chrome.sh `scripts/release-build.sh` copies source `Dockerfile.base` into the release tree as `Dockerfile` and ships `Dockerfile.example` as the on-demand template for root `.codegeist/Dockerfile`; do not add a tracked root `Dockerfile` to the source -checkout for the kit base image. +checkout for the kit base image. The source and generated runtime trees both ship +the canonical 0BSD `LICENSE`. ## OpenCode Workspace @@ -1021,3 +1052,13 @@ Prefer: - The base image currently keeps the copied Codegeist/planner toolchain intact; future work can split generic tools from project-specific features when there is a concrete consumer need. + +The public roadmap listing is maintained at +. Contributor-sized work should +start from a GitHub Issue and, when implementation detail needs durable handoff, +a linked specification under `docs/tasks/`. + +## License + +This repository and its generated runtime release are available under the +[Zero-Clause BSD (`0BSD`) license](LICENSE). diff --git a/README_release.md b/README_release.md index 6fb0522..11f6078 100644 --- a/README_release.md +++ b/README_release.md @@ -17,6 +17,37 @@ tests, and local AI workflow support. The image toolchain includes PowerShell as `pwsh` for cross-platform shell and automation work, Task with Bash completion, shared terminal-capture tools for documentation previews, plus shared QEMU and security-scan tools for infrastructure checks inside consuming devcontainers. +The runtime tree includes the repository's [`LICENSE`](LICENSE) and is +distributed under the Zero-Clause BSD (`0BSD`) license. + +## Project And Contributions + +Changes to the kit belong on the source repository's `main` branch, not in this +generated `release` tree or a consuming repository's `.devcontainer/` checkout. +Use the source repository's +[contributor guide](https://github.com/codegeist-ai/codegeist-devcontainer-kit/blob/main/CONTRIBUTING.md), +[GitHub Issues](https://github.com/codegeist-ai/codegeist-devcontainer-kit/issues), +[task guide](https://github.com/codegeist-ai/codegeist-devcontainer-kit/blob/main/docs/tasks/README.md), +and [Codegeist roadmap listing](https://github.com/users/codegeist-ai/projects/1) +to propose and track work. + +In a source `main` checkout, run `task check` as the normal fast contributor +check. Run the broader `task tests-run` suite when a change affects the image, +Dev Containers lifecycle, Docker/Compose behavior, QEMU, or browser runtime. +The fast check uses cleanup-trapped OS temporary state and leaves no repo-local +test directory behind. These source tasks are intentionally omitted from the +generated runtime tree. + +Codegeist's account-wide +[Code of Conduct](https://github.com/codegeist-ai/.github/blob/main/CODE_OF_CONDUCT.md), +[Security Policy](https://github.com/codegeist-ai/.github/blob/main/SECURITY.md), +and [Support Policy](https://github.com/codegeist-ai/.github/blob/main/SUPPORT.md) +apply without being duplicated in this runtime tree. + +## Release Notes + +- The generated runtime manifest includes the canonical root `LICENSE`, so the + license travels with every `.devcontainer/` release checkout. ## Consumer Setup diff --git a/Taskfile.yaml b/Taskfile.yaml index ed78969..7adc395 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -19,6 +19,7 @@ # - tests/code-open-test.sh # - scripts/chrome.sh # - tests/browser-open-test.sh +# - tests/release-build.sh version: '3' @@ -38,6 +39,17 @@ vars: sh: printf '%s' "${CONTAINER_GID:-${UID:-$(id -u)}}" tasks: + check: + desc: Run fast deterministic contributor checks + cmds: + - >- + bash -n + "{{.TASKFILE_DIR}}/entrypoint.sh" + "{{.TASKFILE_DIR}}/initialize.sh" + "{{.TASKFILE_DIR}}"/scripts/*.sh + "{{.TASKFILE_DIR}}"/tests/*.sh + - '"{{.TASKFILE_DIR}}/tests/release-build.sh"' + docker-build: desc: Build the generic devcontainer kit image cmds: diff --git a/docs/memory-bank/chat.md b/docs/memory-bank/chat.md index 2de0ce1..6050dbb 100644 --- a/docs/memory-bank/chat.md +++ b/docs/memory-bank/chat.md @@ -23,13 +23,18 @@ simultaneous first-time `BRANCH` starts. - OpenCode work should continue from this repository root in the current maintenance checkout. +- The repository-local contributor baseline now targets source `main`: 0BSD + licensing, a local contribution guide, Issue-to-task-to-PR linkage, and + read-only CI all use `task check` as the normal fast contract. +- Contributor rollout remains open until the pending public Issues, pull request, + and roadmap/GitHub state are created outside this repository. ## Current State - Local default branch is `main`. -- `.devcontainer/` and `.opencode/` are checked-out shared submodules in this - development repository. Do not edit them directly during normal project work - unless the task is explicit submodule work. +- `.devcontainer/` and `.opencode/` are configured shared submodules in this + development repository. When initialized, do not edit them directly during + normal project work unless the task is explicit submodule work. - `.devcontainer` is a runtime-release submodule. Release workflows may update its gitlink to the latest pushed `origin/release` commit, but should not automatically commit that parent gitlink after publishing unless the user asks. @@ -201,9 +206,12 @@ must not open VS Code or start/remove containers. - Tests should exercise the real Dev Containers lifecycle when behavior depends on VS Code or the Dev Containers CLI integration. -- Test fixtures now use repo-local ignored temp roots (`.test-tmp/` and - `.browser-smoke-tmp/`) because Docker bind mounts in this workspace cannot rely - on arbitrary `/tmp` paths being visible to the daemon. +- Docker-backed broad-suite fixtures use repo-local ignored temp roots + (`.test-tmp/` and `.browser-smoke-tmp/`) because bind mounts cannot rely on + arbitrary `/tmp` paths being visible to the daemon. The normal `task check` + release fixture does not need Docker: it copies only explicit release source + inputs into cleanup-trapped OS temporary state and leaves no repo-local test + directory behind. - Browser UI verification uses `tests/browser-ui-cdp.mjs`, a Node 24 Chrome DevTools Protocol driver invoked by `tests/browser-smoke.sh`. It covers both headless rendering and the real local VS Code failure shape: a Dev Containers @@ -222,9 +230,11 @@ insecure. Manual Google sign-in succeeded after launching `chrome https://accounts.google.com` from the terminal with the updated launcher. Plain `chrome` now uses workspace-local `.chrome` by default. -- After code, script, or workflow changes, run the complete `task tests-run` - suite before handoff when the environment allows it. If the environment blocks - the full suite, report the blocker and list targeted checks that passed. +- Run `task check` for normal contributor changes. Run the complete + `task tests-run` suite when image, Dev Containers lifecycle, Docker/Compose, + QEMU, browser runtime, or release-relevant integration behavior changes; if + the environment blocks a relevant full suite, report the blocker and targeted + checks that passed. - Runtime releases are published from clean `main` with `task release-build`; use `--push` only when the branch should be pushed immediately. This repository publishes runtime artifacts through the `release` branch only, not through @@ -344,6 +354,7 @@ ## Useful Commands ```bash +task check task tests-run task qemu-alpine-smoke task code-open diff --git a/docs/tasks/README.md b/docs/tasks/README.md index 65d115f..54abf98 100644 --- a/docs/tasks/README.md +++ b/docs/tasks/README.md @@ -1,7 +1,8 @@ # Task Docs This directory stores lightweight, resumable task handoff files for this -repository. +repository. GitHub Issues are the public discussion and tracking entrypoint; +local task files retain implementation detail that is useful across sessions. ## Conventions @@ -11,6 +12,8 @@ repository. - A task is represented either by a standalone markdown file or by `task.md` inside a task directory, never both. - Durable task documentation stays in English. +- New public-facing tasks include a `Public Tracking` field. Use `pending issue + creation` until an Issue exists, then replace it with the Issue URL. ## Status Values @@ -20,3 +23,20 @@ repository. - `solved` - implementation and verification are complete. - `finalized` - solved task has been reviewed for related docs and task state. - `cancelled` - task is intentionally closed without implementation. + +## Issue To Task To Pull Request + +1. Open or identify a GitHub Issue for the public problem statement. +2. Create or update the local task specification with the Issue URL in `Public + Tracking`, concrete acceptance criteria, file targets, non-goals, and + verification. +3. Keep task status current as the work is specified, implemented, verified, or + cancelled. +4. Link both the GitHub Issue and local task path from the pull request. +5. Let the pull request close the Issue when the accepted implementation is + merged; update the local task to `solved` or `finalized` in the same change + when appropriate. + +A local task may be drafted before public tracking exists, but `pending issue +creation` means the contributor rollout is incomplete rather than privately +tracked forever. diff --git a/docs/tasks/T002_document_host_capability_matrix.md b/docs/tasks/T002_document_host_capability_matrix.md new file mode 100644 index 0000000..c0cac5b --- /dev/null +++ b/docs/tasks/T002_document_host_capability_matrix.md @@ -0,0 +1,50 @@ +# Document The Host Capability Matrix + +- ID: `T002` +- Type: `docs` +- Status: `open` +- Parent: `none` +- Public Tracking: `pending issue creation` + +## Goal + +Add one concise host-capability matrix that tells contributors which local +capabilities are needed for the normal check, devcontainer use, and each broad +integration-test category. + +## Context + +The current README documents Docker, KVM, display forwarding, browsers, and QEMU +in their individual sections, but it does not provide one entry-point table for +contributors deciding which checks their host can run. This documentation task +is intentionally suitable for a first contribution and remains unimplemented. + +## Acceptance Criteria + +- The source README has one compact matrix covering `task check`, normal VS Code + Dev Containers use, Docker-backed integration tests, KVM/QEMU tests, and + visible browser tests. +- Each row distinguishes required host capabilities from optional capabilities + and links to existing detailed sections instead of repeating them. +- The matrix does not promise support for an untested host, display transport, + or virtualization configuration. +- Contributor documentation points to the matrix where host prerequisites are + discussed. + +## Files + +- `README.md` +- `CONTRIBUTING.md` + +## Non-Goals + +- Changing the image, Compose configuration, or test behavior. +- Adding support for a new operating system or container runtime. +- Rewriting the existing detailed browser, QEMU, or test documentation. + +## Verification + +- Run `task check`. +- Review every matrix link from the rendered Markdown. +- Confirm every claimed capability is backed by an existing test or documented + runtime contract. diff --git a/docs/tasks/T003_add_read_only_release_preview.md b/docs/tasks/T003_add_read_only_release_preview.md new file mode 100644 index 0000000..30c7529 --- /dev/null +++ b/docs/tasks/T003_add_read_only_release_preview.md @@ -0,0 +1,54 @@ +# Add A Read-Only Release Preview + +- ID: `T003` +- Type: `feature` +- Status: `open` +- Parent: `none` +- Public Tracking: `pending issue creation` + +## Goal + +Let contributors materialize and inspect the exact runtime-only release tree +without creating a commit, updating a Git ref, or publishing a branch. + +## Context + +The current `scripts/release-build.sh` owns the runtime file manifest and creates +the generated release commit after the heavyweight release gate. The focused +release test exercises that workflow in a temporary fixture, but there is no +contributor command that only writes a preview tree. This capability remains +unimplemented. + +## Acceptance Criteria + +- A documented command writes the release tree to an explicit temporary or + caller-selected directory without changing repository refs or commits. +- Preview and publication use one canonical runtime manifest; file lists are not + duplicated in separate implementation paths. +- The preview maps `Dockerfile.base` to `Dockerfile` and `README_release.md` to + `README.md` exactly like release publication. +- A deterministic test compares preview contents and paths with the existing + release assembly contract. +- Existing maintainer-only publication and full-suite verification gates remain + unchanged. + +## Files + +- `Taskfile.yaml` +- `scripts/release-build.sh` +- `tests/release-build.sh` +- `README.md` +- `CONTRIBUTING.md` + +## Non-Goals + +- Publishing the `release` branch. +- Weakening the clean-`main` or full-suite release gate. +- Building the devcontainer image during preview. + +## Verification + +- Run the new focused preview test. +- Run `task check`. +- Confirm `git status --short --branch` and relevant local refs are unchanged by + the preview command. diff --git a/docs/tasks/T004_audit_mutable_toolchain_inputs.md b/docs/tasks/T004_audit_mutable_toolchain_inputs.md new file mode 100644 index 0000000..2d5435e --- /dev/null +++ b/docs/tasks/T004_audit_mutable_toolchain_inputs.md @@ -0,0 +1,64 @@ +# Audit Mutable Toolchain Inputs + +- ID: `T004` +- Type: `chore` +- Status: `open` +- Parent: `none` +- Public Tracking: `pending issue creation` +- Contribution Level: `intermediate` +- Effort: `medium` + +## Goal + +Inventory mutable build-time installer and package inputs, assess their +reproducibility risks, and define a small set of focused improvements that can be +implemented and reviewed independently. + +## Context + +`Dockerfile.base` currently combines explicitly versioned downloads with +`releases/latest` assets, scripts fetched from `main`, unversioned npm and pip +packages, moving APT repositories, and installers executed from network pipes. +Tests verify the resulting tools, but the repository has no complete input +inventory, integrity classification, or documented update policy. This audit and +its proposed improvements remain unimplemented. + +## Acceptance Criteria + +- A repo-owned document inventories every network-fetched image-build input in + `Dockerfile.base`, including its source, current selector, architecture + assumptions, available integrity mechanism, and existing verification. +- Inputs are classified consistently as immutable, version-selected, or mutable. +- The audit prioritizes risks without claiming the complete image is + reproducible when APT repositories or other moving sources remain. +- The audit proposes a bounded first set of improvements, with an update method + and focused verification strategy for each proposal. +- Proposed improvements are split into reviewable follow-up tasks or Issues + rather than a single bulk pinning change. +- Existing intentional choices, including tools that currently follow latest + upstream channels, are identified instead of silently reclassified as defects. + +## Files + +- `Dockerfile.base` +- `tests/docker-build.sh` +- `README.md` +- `README_release.md` +- `docs/` + +## Non-Goals + +- Pinning, upgrading, or replacing packages and installers as part of the audit. +- Generating a lockfile for Debian APT repositories. +- Claiming bit-for-bit image reproducibility. +- Running or publishing a release. + +## Verification + +- Compare the inventory against every URL, package-manager install, and external + repository declaration in `Dockerfile.base`. +- Confirm each proposed improvement names an update path and deterministic + focused check. +- Run `task check` for documentation and release-contract validation. +- Confirm no Dockerfile, installer, package selector, or runtime behavior changed + while completing the audit. diff --git a/docs/tasks/template.md b/docs/tasks/template.md index 50b5b58..bd09453 100644 --- a/docs/tasks/template.md +++ b/docs/tasks/template.md @@ -4,6 +4,7 @@ - Type: `` - Status: `open` - Parent: `none` +- Public Tracking: `pending issue creation` ## Goal diff --git a/scripts/release-build.sh b/scripts/release-build.sh index 0513642..fa8b0f6 100755 --- a/scripts/release-build.sh +++ b/scripts/release-build.sh @@ -17,6 +17,7 @@ # Related files: # - ../Taskfile.yaml # - ../README_release.md +# - ../LICENSE # - ../devcontainer.json # - ../docker-compose.yml # - ../Dockerfile.base @@ -36,6 +37,7 @@ runtime_files=( ".local.env.example" ".oc_local.gitignore.example" ".oc_local.opencode.json.example" + "LICENSE" "Dockerfile.example" "compose.local.yml.example" "devcontainer.json" diff --git a/tests/helpers.sh b/tests/helpers.sh index 9f78ef9..a315e3e 100755 --- a/tests/helpers.sh +++ b/tests/helpers.sh @@ -378,20 +378,28 @@ create_git_fixture_repo() { local fixture_dir="$1" create_fixture_repo "$fixture_dir" - git -C "$fixture_dir" init >/dev/null - git -C "$fixture_dir" config user.name "Test User" - git -C "$fixture_dir" config user.email "test@example.com" + create_git_repo "$fixture_dir" git -C "$fixture_dir" add . git -C "$fixture_dir" commit -m "initial fixture" >/dev/null } create_git_repo() { local repo_dir="$1" + local empty_template_dir="$repo_dir/.git-empty-template" - mkdir -p "$repo_dir" - git -C "$repo_dir" init -b main >/dev/null - git -C "$repo_dir" config user.name "Test User" - git -C "$repo_dir" config user.email "test@example.com" + mkdir -p "$repo_dir" "$empty_template_dir" + if ! git -C "$repo_dir" init --template="$empty_template_dir" -b main >/dev/null; then + rm -rf "$empty_template_dir" + return 1 + fi + rm -rf "$empty_template_dir" + + # Fixture commits must not inherit signing, hooks, or template behavior from + # the contributor's Git configuration. + git -C "$repo_dir" config --local commit.gpgSign false + git -C "$repo_dir" config --local core.hooksPath /dev/null + git -C "$repo_dir" config --local user.name "Test User" + git -C "$repo_dir" config --local user.email "test@example.com" } create_kit_submodule_repo() { diff --git a/tests/release-build.sh b/tests/release-build.sh index 9091433..c945eb2 100755 --- a/tests/release-build.sh +++ b/tests/release-build.sh @@ -4,8 +4,9 @@ # Why this exists: # - Protects the branch contract consumed by downstream repositories that pin # this kit as a `.devcontainer` submodule. -# - Exercises the real `scripts/release-build.sh` workflow in a temporary Git -# repository so the current checkout is not branch-mutated. +# - Exercises the real `scripts/release-build.sh` workflow from a bounded source +# input set in a cleanup-trapped OS temporary Git repository, so ignored local +# state is not copied and the current checkout is not changed. # # Related files: # - ../scripts/release-build.sh @@ -18,29 +19,62 @@ script_dir="$(dirname "$(readlink -f "$0")")" # shellcheck source=./helpers.sh source "$script_dir/helpers.sh" -local_suite=0 -if [ -z "${suite_tmp_dir:-}" ]; then - setup_suite - local_suite=1 -fi - -if [ "$local_suite" -eq 1 ]; then - trap cleanup_suite EXIT -fi - -release_repo="$suite_tmp_dir/release-build-fixture" +test_tmp_dir="$(mktemp -d "${TMPDIR:-/tmp}/codegeist-release-build-test.XXXXXX")" +release_repo="$test_tmp_dir/release-build-fixture" release_branch="release" -expected_files="$suite_tmp_dir/release-build-expected-files.txt" -actual_files="$suite_tmp_dir/release-build-actual-files.txt" -missing_verification_log="$suite_tmp_dir/release-build-missing-verification.log" +expected_files="$test_tmp_dir/release-build-expected-files.txt" +actual_files="$test_tmp_dir/release-build-actual-files.txt" +dirty_worktree_log="$test_tmp_dir/release-build-dirty-worktree.log" +missing_verification_log="$test_tmp_dir/release-build-missing-verification.log" +clean_readme="$test_tmp_dir/README_release.md" +release_source_files=( + ".gitignore" + ".local.env.example" + ".oc_local.gitignore.example" + ".oc_local.opencode.json.example" + "Dockerfile.base" + "Dockerfile.example" + "LICENSE" + "README_release.md" + "compose.local.yml.example" + "devcontainer.json" + "docker-compose.yml" + "entrypoint.sh" + "initialize.sh" + "scripts/chrome.sh" + "scripts/release-build.sh" +) + +cleanup_release_test() { + rm -rf "$test_tmp_dir" +} + +trap cleanup_release_test EXIT create_git_repo "$release_repo" -copy_project_files "$release_repo" +for source_file in "${release_source_files[@]}"; do + mkdir -p "$release_repo/$(dirname "$source_file")" + cp -p "$project_root/$source_file" "$release_repo/$source_file" +done git -C "$release_repo" add . git -C "$release_repo" commit -m "initial devcontainer kit" >/dev/null main_commit="$(git -C "$release_repo" rev-parse main)" +[[ "$(git -C "$release_repo" config --local --get commit.gpgSign)" = "false" ]] \ + || fail "fixture repository did not disable inherited commit signing" +[[ "$(git -C "$release_repo" config --local --get core.hooksPath)" = "/dev/null" ]] \ + || fail "fixture repository did not disable inherited Git hooks" + +cp -p "$release_repo/README_release.md" "$clean_readme" +printf '\nDirty worktree marker.\n' >>"$release_repo/README_release.md" +if (cd "$release_repo" && scripts/release-build.sh) >"$dirty_worktree_log" 2>&1; then + fail "release-build accepted an uncommitted source change" +fi +grep -F "working tree must be clean" "$dirty_worktree_log" >/dev/null \ + || fail "release-build did not explain the clean-worktree requirement" +cp -p "$clean_readme" "$release_repo/README_release.md" + if (cd "$release_repo" && scripts/release-build.sh) >"$missing_verification_log" 2>&1; then fail "release-build accepted a commit without full-suite verification" fi @@ -74,6 +108,7 @@ cat >"$expected_files" <<'EOF' .oc_local.opencode.json.example Dockerfile Dockerfile.example +LICENSE README.md compose.local.yml.example devcontainer.json @@ -94,6 +129,9 @@ diff -u "$release_repo/README_release.md" <(git -C "$release_repo" show "$releas diff -u "$release_repo/Dockerfile.base" <(git -C "$release_repo" show "$release_branch:Dockerfile") \ || fail "release branch Dockerfile does not match Dockerfile.base" +diff -u "$release_repo/LICENSE" <(git -C "$release_repo" show "$release_branch:LICENSE") \ + || fail "release branch LICENSE does not match source LICENSE" + if git -C "$release_repo" show "$release_branch:Dockerfile.example" | grep -Eiq '^[[:space:]]*FROM([[:space:]]|$)'; then fail "release branch Dockerfile.example must not contain FROM" fi @@ -105,4 +143,4 @@ fi [[ "$(git -C "$release_repo" log -1 --format=%s "$release_branch")" = "chore(release): update devcontainer runtime branch" ]] \ || fail "release branch commit subject is wrong" -pass "release-build requires verification and creates a runtime-only branch" +pass "release-build rejects dirty source and creates the exact runtime-only branch"