v0.1 step 1: Dockerfile + per-language toolchain smoke
Monolith image with every toolchain in the spec: - Python 3.12 + uv/ruff/mypy/pytest/pip-audit/semgrep - Node 22 LTS + bun - Go 1.22 + govulncheck/staticcheck - Rust stable + cargo-audit/cargo-deny - Ruby 3.x + bundler-audit - PHP 8.x + composer/phpstan - JDK 17 + 21 + Maven + Gradle - .NET 8 SDK - Swift 5.9.2 - Kotlin 1.9.25 - clang + cmake + valgrind + ASan/UBSan/TSan - bash + shellcheck smoke.sh proves each toolchain compiles + runs a hello-world. compose.yml uses the existing 'sulkta' bridge network. No API yet (steps 2-3); no MCP yet (step 7); no runner yet (step 4). This is the foundation. NOTE: docker build + smoke verification not yet run — sandbox doesn't have docker. Needs `docker compose build && docker compose up` on Lucy or any real Docker host before we trust the Dockerfile. Spec: memory/spec-crafting-table.md
This commit is contained in:
parent
5bd1b1de7e
commit
4e668a79e1
5 changed files with 619 additions and 1 deletions
48
.gitignore
vendored
Normal file
48
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
.mypy_cache/
|
||||||
|
.ruff_cache/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Node / TS
|
||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Rust
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Go
|
||||||
|
/bin/
|
||||||
|
|
||||||
|
# Java / Kotlin / Gradle / Maven
|
||||||
|
build/
|
||||||
|
out/
|
||||||
|
.gradle/
|
||||||
|
*.class
|
||||||
|
*.jar
|
||||||
|
.mvn/
|
||||||
|
|
||||||
|
# .NET
|
||||||
|
.dotnet/
|
||||||
|
obj/
|
||||||
|
|
||||||
|
# Swift
|
||||||
|
.swiftpm/
|
||||||
|
.build/
|
||||||
|
*.xcodeproj/
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
.cache/
|
||||||
|
.env
|
||||||
|
*.log
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Editor
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
263
Dockerfile
Normal file
263
Dockerfile
Normal file
|
|
@ -0,0 +1,263 @@
|
||||||
|
# crafting-table v0.1 — polyglot dev/build/audit container
|
||||||
|
#
|
||||||
|
# Step 1 of 10: monolith image with every toolchain in the spec.
|
||||||
|
# Spec: Sulkta-Coop/openclaw-workspace/memory/spec-crafting-table.md
|
||||||
|
#
|
||||||
|
# Toolchain version pins (bump these to upgrade):
|
||||||
|
# NODE_VERSION 22.11.0 (LTS)
|
||||||
|
# GO_VERSION 1.22.10
|
||||||
|
# RUST_CHANNEL stable
|
||||||
|
# BUN_VERSION latest (rolling — pinned at install only)
|
||||||
|
# DOTNET_VERSION 8.0
|
||||||
|
# SWIFT_VERSION 5.9.2
|
||||||
|
# KOTLIN_VERSION 1.9.25
|
||||||
|
# GRADLE_VERSION 8.10
|
||||||
|
# JDK 17 (default) + 21 (alongside, via JAVA_HOME_21)
|
||||||
|
#
|
||||||
|
# Image runs as non-root user `crafter` (uid 1000) with passwordless sudo.
|
||||||
|
# Persistent caches mounted at /caches/{cargo,maven,gradle,npm,pip}.
|
||||||
|
# Workspace at /workspace. Per-job state at /data.
|
||||||
|
|
||||||
|
FROM debian:bookworm-slim
|
||||||
|
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive \
|
||||||
|
LANG=C.UTF-8 \
|
||||||
|
LC_ALL=C.UTF-8
|
||||||
|
|
||||||
|
# ---------- Toolchain version pins ----------
|
||||||
|
ENV NODE_VERSION=22.11.0 \
|
||||||
|
GO_VERSION=1.22.10 \
|
||||||
|
DOTNET_CHANNEL=8.0 \
|
||||||
|
SWIFT_VERSION=5.9.2 \
|
||||||
|
SWIFT_PLATFORM=ubuntu22.04 \
|
||||||
|
KOTLIN_VERSION=1.9.25 \
|
||||||
|
GRADLE_VERSION=8.10
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 1. System base — apt packages
|
||||||
|
# ============================================================
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
curl wget git ca-certificates gnupg lsb-release apt-transport-https \
|
||||||
|
build-essential pkg-config make cmake ninja-build \
|
||||||
|
jq ripgrep fd-find \
|
||||||
|
valgrind clang lld llvm \
|
||||||
|
python3 python3-pip python3-venv python3-dev \
|
||||||
|
php-cli php-curl php-mbstring php-xml php-zip composer \
|
||||||
|
ruby ruby-dev ruby-bundler \
|
||||||
|
bash shellcheck bats \
|
||||||
|
openjdk-17-jdk-headless \
|
||||||
|
sudo unzip xz-utils zstd \
|
||||||
|
libcurl4 libxml2 libedit2 libsqlite3-0 libpython3-dev \
|
||||||
|
libncurses6 libtinfo6 libgcc-s1 libstdc++6 \
|
||||||
|
libssl-dev libffi-dev \
|
||||||
|
zlib1g-dev liblzma-dev libbz2-dev \
|
||||||
|
locales tzdata \
|
||||||
|
&& ln -sf /usr/bin/fdfind /usr/local/bin/fd \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 2. Node 22 LTS via NodeSource
|
||||||
|
# ============================================================
|
||||||
|
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
|
||||||
|
&& apt-get install -y --no-install-recommends nodejs \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& npm install -g pnpm tsx eslint typescript
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 3. Go (download from go.dev tarball)
|
||||||
|
# ============================================================
|
||||||
|
RUN ARCH="$(dpkg --print-architecture)" \
|
||||||
|
&& case "$ARCH" in \
|
||||||
|
amd64) GOARCH=amd64 ;; \
|
||||||
|
arm64) GOARCH=arm64 ;; \
|
||||||
|
*) echo "Unsupported arch $ARCH" && exit 1 ;; \
|
||||||
|
esac \
|
||||||
|
&& curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${GOARCH}.tar.gz" -o /tmp/go.tgz \
|
||||||
|
&& tar -C /usr/local -xzf /tmp/go.tgz \
|
||||||
|
&& rm /tmp/go.tgz
|
||||||
|
ENV PATH=/usr/local/go/bin:/root/go/bin:$PATH \
|
||||||
|
GOPATH=/root/go
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 4. Microsoft .NET 8 SDK (Microsoft apt repo for bookworm/12)
|
||||||
|
# ============================================================
|
||||||
|
RUN curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /usr/share/keyrings/microsoft.gpg \
|
||||||
|
&& echo "deb [signed-by=/usr/share/keyrings/microsoft.gpg] https://packages.microsoft.com/debian/12/prod bookworm main" > /etc/apt/sources.list.d/microsoft.list \
|
||||||
|
&& apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends dotnet-sdk-8.0 \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1 \
|
||||||
|
DOTNET_NOLOGO=1
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 5. Swift (Ubuntu 22.04 tarball — works on Debian bookworm
|
||||||
|
# because bookworm ships the right libicu/libstdc++ baseline)
|
||||||
|
# ============================================================
|
||||||
|
RUN ARCH="$(dpkg --print-architecture)" \
|
||||||
|
&& SWIFT_PLAT="${SWIFT_PLATFORM}" \
|
||||||
|
&& case "$ARCH" in \
|
||||||
|
amd64) SWIFT_TARBALL_NAME="swift-${SWIFT_VERSION}-RELEASE-${SWIFT_PLAT}" ;; \
|
||||||
|
arm64) SWIFT_TARBALL_NAME="swift-${SWIFT_VERSION}-RELEASE-${SWIFT_PLAT}-aarch64" ;; \
|
||||||
|
*) echo "Unsupported arch $ARCH for Swift" && exit 1 ;; \
|
||||||
|
esac \
|
||||||
|
&& apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends libpython3-dev libxml2-dev \
|
||||||
|
libcurl4-openssl-dev libedit-dev libsqlite3-dev libtinfo-dev libncurses-dev \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& curl -fsSL "https://download.swift.org/swift-${SWIFT_VERSION}-release/${SWIFT_PLAT//./}/swift-${SWIFT_VERSION}-RELEASE/${SWIFT_TARBALL_NAME}.tar.gz" -o /tmp/swift.tgz \
|
||||||
|
&& mkdir -p /opt/swift \
|
||||||
|
&& tar -xzf /tmp/swift.tgz -C /opt/swift --strip-components=1 \
|
||||||
|
&& rm /tmp/swift.tgz
|
||||||
|
ENV PATH=/opt/swift/usr/bin:$PATH
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 6. Kotlin compiler (direct download from GitHub release)
|
||||||
|
# ============================================================
|
||||||
|
RUN curl -fsSL "https://github.com/JetBrains/kotlin/releases/download/v${KOTLIN_VERSION}/kotlin-compiler-${KOTLIN_VERSION}.zip" -o /tmp/kotlin.zip \
|
||||||
|
&& unzip -q /tmp/kotlin.zip -d /opt \
|
||||||
|
&& mv /opt/kotlinc /opt/kotlin \
|
||||||
|
&& rm /tmp/kotlin.zip
|
||||||
|
ENV PATH=/opt/kotlin/bin:$PATH
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 7. JDK 21 alongside JDK 17 (Eclipse Temurin via apt)
|
||||||
|
# ============================================================
|
||||||
|
RUN mkdir -p /etc/apt/keyrings \
|
||||||
|
&& curl -fsSL https://packages.adoptium.net/artifactory/api/gpg/key/public | gpg --dearmor -o /etc/apt/keyrings/adoptium.gpg \
|
||||||
|
&& echo "deb [signed-by=/etc/apt/keyrings/adoptium.gpg] https://packages.adoptium.net/artifactory/deb bookworm main" > /etc/apt/sources.list.d/adoptium.list \
|
||||||
|
&& apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends temurin-21-jdk \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 \
|
||||||
|
JAVA_HOME_17=/usr/lib/jvm/java-17-openjdk-amd64 \
|
||||||
|
JAVA_HOME_21=/usr/lib/jvm/temurin-21-jdk-amd64
|
||||||
|
RUN update-alternatives --set java ${JAVA_HOME_17}/bin/java || true \
|
||||||
|
&& update-alternatives --set javac ${JAVA_HOME_17}/bin/javac || true
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 8. Maven (apt) + Gradle (direct download — apt's gradle is ancient)
|
||||||
|
# ============================================================
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends maven \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& curl -fsSL "https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip" -o /tmp/gradle.zip \
|
||||||
|
&& unzip -q /tmp/gradle.zip -d /opt \
|
||||||
|
&& mv /opt/gradle-${GRADLE_VERSION} /opt/gradle \
|
||||||
|
&& rm /tmp/gradle.zip
|
||||||
|
ENV PATH=/opt/gradle/bin:$PATH
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 9. GitHub CLI (gh)
|
||||||
|
# ============================================================
|
||||||
|
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||||
|
&& chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||||
|
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list \
|
||||||
|
&& apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends gh \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 10. yq (Mike Farah, Go binary)
|
||||||
|
# ============================================================
|
||||||
|
RUN ARCH="$(dpkg --print-architecture)" \
|
||||||
|
&& curl -fsSL "https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${ARCH}" -o /usr/local/bin/yq \
|
||||||
|
&& chmod +x /usr/local/bin/yq
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 11. shfmt (Go binary)
|
||||||
|
# ============================================================
|
||||||
|
RUN ARCH="$(dpkg --print-architecture)" \
|
||||||
|
&& curl -fsSL "https://github.com/mvdan/sh/releases/latest/download/shfmt_v3.10.0_linux_${ARCH}" -o /usr/local/bin/shfmt \
|
||||||
|
&& chmod +x /usr/local/bin/shfmt
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 12. Create non-root user `crafter` (uid 1000) with passwordless sudo
|
||||||
|
# and prepare workspace / cache / data dirs
|
||||||
|
# ============================================================
|
||||||
|
RUN useradd -m -u 1000 -s /bin/bash crafter \
|
||||||
|
&& echo "crafter ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/crafter \
|
||||||
|
&& chmod 0440 /etc/sudoers.d/crafter \
|
||||||
|
&& mkdir -p /workspace /caches/cargo /caches/maven /caches/gradle /caches/npm /caches/pip /caches/bun /data \
|
||||||
|
&& chown -R crafter:crafter /workspace /caches /data
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 13. Switch to crafter for user-scoped installs
|
||||||
|
# ============================================================
|
||||||
|
USER crafter
|
||||||
|
WORKDIR /home/crafter
|
||||||
|
|
||||||
|
# Cache env (point tools at the persisted cache dirs)
|
||||||
|
ENV CARGO_HOME=/caches/cargo \
|
||||||
|
RUSTUP_HOME=/home/crafter/.rustup \
|
||||||
|
GRADLE_USER_HOME=/caches/gradle \
|
||||||
|
MAVEN_OPTS="-Dmaven.repo.local=/caches/maven" \
|
||||||
|
NPM_CONFIG_CACHE=/caches/npm \
|
||||||
|
PIP_CACHE_DIR=/caches/pip \
|
||||||
|
BUN_INSTALL=/home/crafter/.bun \
|
||||||
|
PIPX_HOME=/home/crafter/.local/pipx \
|
||||||
|
PIPX_BIN_DIR=/home/crafter/.local/bin
|
||||||
|
|
||||||
|
ENV PATH=/home/crafter/.local/bin:/caches/cargo/bin:/home/crafter/.bun/bin:$PATH
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 14. Rust (rustup, stable) + cargo-audit + cargo-deny
|
||||||
|
# ============================================================
|
||||||
|
RUN curl -fsSL https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal --no-modify-path \
|
||||||
|
&& /caches/cargo/bin/rustup component add clippy rustfmt \
|
||||||
|
&& /caches/cargo/bin/cargo install cargo-audit --locked \
|
||||||
|
&& /caches/cargo/bin/cargo install cargo-deny --locked
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 15. Bun (curl install)
|
||||||
|
# ============================================================
|
||||||
|
RUN curl -fsSL https://bun.sh/install | bash
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 16. Python user tooling: pipx-managed CLI tools
|
||||||
|
# ============================================================
|
||||||
|
RUN python3 -m pip install --user --break-system-packages --no-cache-dir pipx \
|
||||||
|
&& python3 -m pipx ensurepath \
|
||||||
|
&& pipx install uv \
|
||||||
|
&& pipx install ruff \
|
||||||
|
&& pipx install mypy \
|
||||||
|
&& pipx install pytest \
|
||||||
|
&& pipx install pip-audit \
|
||||||
|
&& pipx install semgrep
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 17. Go user tooling: govulncheck + staticcheck
|
||||||
|
# ============================================================
|
||||||
|
RUN go install golang.org/x/vuln/cmd/govulncheck@latest \
|
||||||
|
&& go install honnef.co/go/tools/cmd/staticcheck@latest
|
||||||
|
|
||||||
|
# Make GOPATH bin discoverable for the crafter user
|
||||||
|
ENV PATH=/home/crafter/go/bin:$PATH \
|
||||||
|
GOPATH=/home/crafter/go
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 18. Ruby user tooling: bundler-audit, rubocop
|
||||||
|
# ============================================================
|
||||||
|
RUN gem install --user-install --no-document bundler-audit rubocop || \
|
||||||
|
sudo gem install --no-document bundler-audit rubocop
|
||||||
|
ENV PATH=/home/crafter/.local/share/gem/ruby/3.1.0/bin:$PATH
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 19. PHP user tooling: phpstan, phpunit (composer global)
|
||||||
|
# ============================================================
|
||||||
|
ENV COMPOSER_HOME=/home/crafter/.composer
|
||||||
|
RUN composer global require --no-interaction phpstan/phpstan phpunit/phpunit
|
||||||
|
ENV PATH=/home/crafter/.composer/vendor/bin:$PATH
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 20. Smoke script — bake in
|
||||||
|
# ============================================================
|
||||||
|
COPY --chown=crafter:crafter smoke.sh /usr/local/bin/smoke.sh
|
||||||
|
USER root
|
||||||
|
RUN chmod +x /usr/local/bin/smoke.sh
|
||||||
|
USER crafter
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 21. Final ENV / WORKDIR / CMD
|
||||||
|
# ============================================================
|
||||||
|
WORKDIR /workspace
|
||||||
|
CMD ["/bin/bash"]
|
||||||
87
README.md
87
README.md
|
|
@ -1,3 +1,88 @@
|
||||||
# crafting-table
|
# crafting-table
|
||||||
|
|
||||||
Polyglot dev/build/audit container with autonomous patch loop + email digest. Recipes for every Sulkta repo, structured findings back to clawdforge.
|
Polyglot dev/build/audit container — the build farm for the Sulkta ecosystem.
|
||||||
|
|
||||||
|
## What this is
|
||||||
|
|
||||||
|
A single Docker container with every toolchain we work with, used as a
|
||||||
|
reliable place to compile / test / audit any Sulkta repo regardless of
|
||||||
|
where the caller is — agents, Claude sessions, ad-hoc curl, scheduled cron.
|
||||||
|
|
||||||
|
Eventual surface (v0.1 full): HTTP API + MCP server + project registry +
|
||||||
|
job runner + structured findings + email digest + autonomous patch loop
|
||||||
|
through clawdforge.
|
||||||
|
|
||||||
|
Spec: `Sulkta-Coop/openclaw-workspace/memory/spec-crafting-table.md` (LAN-only).
|
||||||
|
|
||||||
|
## Status — v0.1 step 1 of 10
|
||||||
|
|
||||||
|
- [x] Step 1: Dockerfile + per-language smoke
|
||||||
|
- [ ] Step 2: SQLite ledger + project registry
|
||||||
|
- [ ] Step 3: HTTP API skeleton (FastAPI, port 8810)
|
||||||
|
- [ ] Step 4: Job runner core (asyncio worker pool)
|
||||||
|
- [ ] Step 5: Per-language parsers (Rust / Python / Go / TS first)
|
||||||
|
- [ ] Step 6: Findings extraction + storage
|
||||||
|
- [ ] Step 7: MCP server (stdio JSON-RPC, 8 tools)
|
||||||
|
- [ ] Step 8: Email digest scheduler
|
||||||
|
- [ ] Step 9: Autonomous patch loop (clawdforge integration)
|
||||||
|
- [ ] Step 10: Production recipes — clawdforge, cauldron, tradecraft
|
||||||
|
|
||||||
|
## Toolchains in v0.1
|
||||||
|
|
||||||
|
| Lang | Versions / extras |
|
||||||
|
|----------|--------------------------------------------------------------------|
|
||||||
|
| Python | 3.11 (Debian default) + uv, pipx, pip-audit, ruff, mypy, pytest, semgrep |
|
||||||
|
| Node | 22.11.0 LTS + npm, pnpm, tsx, eslint, typescript |
|
||||||
|
| Bun | latest (rolling) |
|
||||||
|
| Go | 1.22.10 + govulncheck, staticcheck |
|
||||||
|
| Rust | stable (rustup) + clippy, rustfmt, cargo-audit, cargo-deny |
|
||||||
|
| Ruby | 3.1 (Debian default) + bundler, bundler-audit, rubocop |
|
||||||
|
| PHP | 8.2 (Debian default) + composer, phpstan, phpunit |
|
||||||
|
| JDK | 17 (default) + 21 (Temurin, alongside via `JAVA_HOME_21`) |
|
||||||
|
| Maven | 3.x (Debian) |
|
||||||
|
| Gradle | 8.10 |
|
||||||
|
| .NET | 8.0 SDK |
|
||||||
|
| Swift | 5.9.2 (Ubuntu 22.04 tarball — works on Debian bookworm) |
|
||||||
|
| Kotlin | 1.9.25 (compiler) |
|
||||||
|
| C/C++ | clang + lld + cmake + ninja + valgrind |
|
||||||
|
| Bash | bash + shellcheck + bats + shfmt |
|
||||||
|
| Generic | git, jq, yq, ripgrep, fd, gh-cli, curl, wget |
|
||||||
|
|
||||||
|
## Build + smoke
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker network inspect sulkta >/dev/null 2>&1 || docker network create sulkta
|
||||||
|
docker compose build
|
||||||
|
docker compose up
|
||||||
|
# expect: "=== ALL TOOLCHAINS GREEN ===" then exit 0
|
||||||
|
```
|
||||||
|
|
||||||
|
The smoke compiles + runs a hello-world in every language. If it exits 0,
|
||||||
|
the image is good.
|
||||||
|
|
||||||
|
## Image notes
|
||||||
|
|
||||||
|
- Base: `debian:bookworm-slim`. Swift uses the upstream Ubuntu 22.04 tarball
|
||||||
|
which links against bookworm's libicu/libstdc++ baseline.
|
||||||
|
- Runs as non-root user `crafter` (uid 1000) with passwordless sudo.
|
||||||
|
- Volume mount points: `/workspace`, `/caches/{cargo,maven,gradle,npm,pip,bun}`,
|
||||||
|
`/data`. Compose binds these to named volumes so they survive `compose down`.
|
||||||
|
- Network: external `sulkta` bridge (same one clawdforge + cauldron use).
|
||||||
|
Create with `docker network create sulkta` if missing.
|
||||||
|
- Image size baseline is large (8-15 GB expected). Per spec: that's fine.
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── Dockerfile # monolith image with all toolchains
|
||||||
|
├── compose.yml # build + run-smoke wiring
|
||||||
|
├── smoke.sh # per-language hello-world test, baked in at /usr/local/bin/smoke.sh
|
||||||
|
├── README.md
|
||||||
|
├── LICENSE # MIT
|
||||||
|
└── .gitignore
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
|
|
|
||||||
28
compose.yml
Normal file
28
compose.yml
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
# crafting-table v0.1 — step 1 compose.
|
||||||
|
#
|
||||||
|
# Builds the monolith image and runs the smoke test once.
|
||||||
|
# In step 2+ the `command:` is replaced with the API server entrypoint.
|
||||||
|
name: crafting-table
|
||||||
|
|
||||||
|
services:
|
||||||
|
crafting-table:
|
||||||
|
build: .
|
||||||
|
image: crafting-table:local
|
||||||
|
container_name: crafting-table
|
||||||
|
command: ["/usr/local/bin/smoke.sh"]
|
||||||
|
user: crafter
|
||||||
|
working_dir: /workspace
|
||||||
|
volumes:
|
||||||
|
- workspace:/workspace
|
||||||
|
- caches:/caches
|
||||||
|
- data:/data
|
||||||
|
networks: [sulkta]
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
workspace:
|
||||||
|
caches:
|
||||||
|
data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
sulkta:
|
||||||
|
external: true
|
||||||
194
smoke.sh
Executable file
194
smoke.sh
Executable file
|
|
@ -0,0 +1,194 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# crafting-table v0.1 step 1 — toolchain smoke test.
|
||||||
|
#
|
||||||
|
# Runs INSIDE the built image; prints `--version` and a hello-world for
|
||||||
|
# every advertised toolchain. Exits 0 only if every block succeeds.
|
||||||
|
#
|
||||||
|
# Spec: memory/spec-crafting-table.md (toolchain matrix)
|
||||||
|
|
||||||
|
set -eo pipefail
|
||||||
|
|
||||||
|
echo "=== crafting-table smoke ==="
|
||||||
|
echo "user: $(id)"
|
||||||
|
echo "pwd: $(pwd)"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- python"
|
||||||
|
python3 --version
|
||||||
|
python3 -c "print('hello from python')"
|
||||||
|
uv --version
|
||||||
|
ruff --version
|
||||||
|
mypy --version
|
||||||
|
pytest --version
|
||||||
|
pip-audit --version
|
||||||
|
semgrep --version
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- node"
|
||||||
|
node --version
|
||||||
|
node -e "console.log('hello from node')"
|
||||||
|
npm --version
|
||||||
|
pnpm --version
|
||||||
|
tsx --version || true
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- bun"
|
||||||
|
bun --version
|
||||||
|
bun -e "console.log('hello from bun')"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- go"
|
||||||
|
go version
|
||||||
|
mkdir -p /tmp/smoke-go && cd /tmp/smoke-go && go mod init smoke 2>/dev/null || true
|
||||||
|
cat >main.go <<'EOF'
|
||||||
|
package main
|
||||||
|
|
||||||
|
func main() { println("hello from go") }
|
||||||
|
EOF
|
||||||
|
go run main.go
|
||||||
|
cd / && rm -rf /tmp/smoke-go
|
||||||
|
govulncheck -version 2>&1 | head -2 || true
|
||||||
|
staticcheck -version
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- rust"
|
||||||
|
rustc --version
|
||||||
|
cargo --version
|
||||||
|
cargo audit --version
|
||||||
|
cargo deny --version
|
||||||
|
cat >/tmp/smoke.rs <<'EOF'
|
||||||
|
fn main() { println!("hello from rust"); }
|
||||||
|
EOF
|
||||||
|
rustc /tmp/smoke.rs -o /tmp/smoke && /tmp/smoke
|
||||||
|
rm /tmp/smoke /tmp/smoke.rs
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- ruby"
|
||||||
|
ruby --version
|
||||||
|
ruby -e "puts 'hello from ruby'"
|
||||||
|
bundler --version
|
||||||
|
bundle-audit version 2>&1 | head -1 || true
|
||||||
|
rubocop --version
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- php"
|
||||||
|
php --version | head -1
|
||||||
|
php -r "echo 'hello from php', PHP_EOL;"
|
||||||
|
composer --version
|
||||||
|
phpstan --version 2>&1 | head -1
|
||||||
|
phpunit --version | head -1
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- jdk 17 (default)"
|
||||||
|
java -version 2>&1 | head -1
|
||||||
|
javac -version
|
||||||
|
cat >/tmp/Smoke.java <<'EOF'
|
||||||
|
public class Smoke { public static void main(String[] a){ System.out.println("hello from java 17"); } }
|
||||||
|
EOF
|
||||||
|
javac /tmp/Smoke.java -d /tmp && java -cp /tmp Smoke
|
||||||
|
rm /tmp/Smoke.java /tmp/Smoke.class
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- jdk 21 (alongside)"
|
||||||
|
"$JAVA_HOME_21/bin/java" -version 2>&1 | head -1
|
||||||
|
"$JAVA_HOME_21/bin/javac" -version
|
||||||
|
cat >/tmp/Smoke21.java <<'EOF'
|
||||||
|
public class Smoke21 { public static void main(String[] a){ System.out.println("hello from java 21"); } }
|
||||||
|
EOF
|
||||||
|
"$JAVA_HOME_21/bin/javac" /tmp/Smoke21.java -d /tmp && "$JAVA_HOME_21/bin/java" -cp /tmp Smoke21
|
||||||
|
rm /tmp/Smoke21.java /tmp/Smoke21.class
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- maven"
|
||||||
|
mvn -version | head -1
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- gradle"
|
||||||
|
gradle -version 2>&1 | grep -E '^Gradle ' | head -1
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- kotlin"
|
||||||
|
kotlinc -version 2>&1 | head -1
|
||||||
|
cat >/tmp/smoke.kt <<'EOF'
|
||||||
|
fun main() { println("hello from kotlin") }
|
||||||
|
EOF
|
||||||
|
kotlinc /tmp/smoke.kt -include-runtime -d /tmp/smoke.jar 2>/dev/null
|
||||||
|
java -jar /tmp/smoke.jar
|
||||||
|
rm /tmp/smoke.kt /tmp/smoke.jar
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- .net 8"
|
||||||
|
dotnet --version
|
||||||
|
mkdir -p /tmp/smoke-dotnet && cd /tmp/smoke-dotnet
|
||||||
|
dotnet new console -o app -n Smoke --force >/dev/null
|
||||||
|
cd app
|
||||||
|
# Suppress NuGet first-run noise; just run the hello-world.
|
||||||
|
dotnet run --nologo 2>&1 | tail -3
|
||||||
|
cd / && rm -rf /tmp/smoke-dotnet
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- swift"
|
||||||
|
swift --version 2>&1 | head -1
|
||||||
|
cat >/tmp/smoke.swift <<'EOF'
|
||||||
|
print("hello from swift")
|
||||||
|
EOF
|
||||||
|
swift /tmp/smoke.swift
|
||||||
|
rm /tmp/smoke.swift
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- clang/c"
|
||||||
|
clang --version | head -1
|
||||||
|
cat >/tmp/smoke.c <<'EOF'
|
||||||
|
#include <stdio.h>
|
||||||
|
int main(void){puts("hello from c");return 0;}
|
||||||
|
EOF
|
||||||
|
clang /tmp/smoke.c -o /tmp/smoke-c && /tmp/smoke-c
|
||||||
|
rm /tmp/smoke.c /tmp/smoke-c
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- clang++/cpp"
|
||||||
|
clang++ --version | head -1
|
||||||
|
cat >/tmp/smoke.cpp <<'EOF'
|
||||||
|
#include <iostream>
|
||||||
|
int main(){std::cout<<"hello from cpp"<<std::endl;return 0;}
|
||||||
|
EOF
|
||||||
|
clang++ -std=c++17 /tmp/smoke.cpp -o /tmp/smoke-cpp && /tmp/smoke-cpp
|
||||||
|
rm /tmp/smoke.cpp /tmp/smoke-cpp
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- cmake + ninja"
|
||||||
|
cmake --version | head -1
|
||||||
|
ninja --version
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- valgrind"
|
||||||
|
valgrind --version
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- bash + shellcheck + bats + shfmt"
|
||||||
|
bash --version | head -1
|
||||||
|
shellcheck --version | head -2 | tail -1
|
||||||
|
bats --version
|
||||||
|
shfmt --version
|
||||||
|
cat >/tmp/smoke.sh <<'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
echo "hello from bash"
|
||||||
|
EOF
|
||||||
|
chmod +x /tmp/smoke.sh
|
||||||
|
bash /tmp/smoke.sh
|
||||||
|
shellcheck /tmp/smoke.sh && echo "shellcheck clean"
|
||||||
|
rm /tmp/smoke.sh
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "--- generic tools"
|
||||||
|
git --version
|
||||||
|
jq --version
|
||||||
|
rg --version | head -1
|
||||||
|
fd --version
|
||||||
|
gh --version | head -1
|
||||||
|
yq --version
|
||||||
|
curl --version | head -1
|
||||||
|
wget --version | head -1
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "=== ALL TOOLCHAINS GREEN ==="
|
||||||
Loading…
Add table
Add a link
Reference in a new issue