Skip to content

v0.2.0 - #3

Merged
peaklabs-dev merged 63 commits into
mainfrom
next
Oct 30, 2026
Merged

peaklabs-dev merged 63 commits into
mainfrom
next

Conversation

@peaklabs-dev

@peaklabs-dev peaklabs-dev commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

Breaking Changes

  • Compress the layers with zstd instead of gzip, zstd is faster, more modern and compresses better than gzip, pulling needs Docker Engine 23.0 or later

Security

  • Harden the image against a checkout with a permissive umask, every file the build copies from the repository gets its mode from the Dockerfile, so no build can make /usr, /usr/local or /usr/local/bin writable for every user.
  • Warn in README.md that a bind mount opens the databases to every user on the host who can reach the directory, and show how to close it
  • Make release tags immutable
    • Refuse to overwrite or delete a release tag such as 3.54.1-v0.2.0 on Docker Hub by using the ag mutability setting on docker hub with a strict patter.
    • Refuse to updated, force push or delete the git tag of a release by using tag protection rule on GitHub
  • Refuse to delete or force-push main, next, release and maintenance branches by using branch protection rules on GitHub
  • Harden the CI workflows
    • Grant every job the least permissions it needs and state the reason for every write permission
    • Keep the Docker Hub credentials in the release environment, which only the branches that release can use, with a token that can push but not delete
    • Keep the tokens that delete images in the cleanup environment, which only main can use and a maintainer approves for every run
    • Lock every action and the actions it calls to a commit in .github/workflows/actions.lock, name actions by their release tag, and fail the lint job when the lockfile is stale
    • Pin the binfmt image by tag and digest, it runs privileged and installs the QEMU of every emulated build
    • Allow the workflows only the events they use, so pull_request_target, workflow_run and comment events start no run
    • Run without the GitHub Actions cache, layer caches and cached tool binaries, so no run restores what another run wrote
    • Lint the workflows with jactionlint pedantic, which includes the audits of zizmor, and fail on every warning

Added

  • Add the shell options sqlite.org recommends for a full-featured shell: .recover and .dbinfo, the sqlite_dbpage and sqlite_stmt virtual tables, the sqlite_offset() function, comments in EXPLAIN output and EXPLAIN of statements that call functions the shell does not know
  • Build reproducibly, a rebuild of the same commit gives the same image digest per platform, and the created date of the image and its org.opencontainers.image.created label are the date of that commit
  • Publish prereleases from next and the release branches, tagged like 3.54.1-v0.2.0-beta.1, and the moving preview tag
  • Publish older SQLite lines such as 3.53 next to the newest, built with the same image version and tagged like 3.53.4-v0.2.0, 3.53.4 and 3.53
  • Builds for linux/arm/v6, linux/ppc64le, linux/s390x and linux/386, eight platforms in total
  • Publish the image of every pull request from a branch of this repository as ghcr.io/peakimages/sqlite:pr-<number>, so a change can be tried before it is merged

Changed

  • Let any uid write the databases, /var/lib/sqlite is 0777 and the entrypoint creates databases with mode 0666, which their -wal and -shm files take, so the application can run as any user and not only as 65532 or root
  • Replace the release process, RELEASE.md describes it
    • Keep the image versions in release.json, stable.image for main and the maintenance branches and preview.image for next and the release branches
    • Pin SQLite in src/upstream.json, one entry per line, instead of src/version.json
    • Release from main, next, release branches such as release/v0.3 and maintenance branches such as v1.x and v0.1.x
    • Select the stage and the version with scripts/release.sh, which offers the versions the branch allows and preselects the bump the commits need
    • Publish nothing while release.json sets 0.0.0, the version a new repository starts with, scripts/release.sh offers 0.1.0 or 1.0.0 as its first release
    • Plan the image version, the releases and the moving tags with scripts/plan-version.sh, which also reports what a push publishes
    • Publish every release a push of release.json or src/upstream.json names and whose tag does not exist yet, never as a draft
    • Move latest, preview and every prefix of a SQLite version to their place among all published tags, so a release of an older line never moves a tag back
    • Check every SQLite line of main, the maintenance branches and the major release branches twice a day and open one pull request per bump, which supersedes the older ones
    • Verify a new SQLite release against its release notes and its tagged check-in on sqlite.org
    • Merge main forward into next and the release branches after every release
    • Tag releases in git and on GitHub with a leading v, v3.54.1-v0.2.0, the image tags stay 3.54.1-v0.2.0, and rename the tags and releases of the earlier versions to match
  • Rework the CI workflows for the new release process
    • Split the build, test and release workflows, the release workflow calls the build workflow and the build workflow calls the tests
    • Build every SQLite line for every platform once, test those builds and publish exactly them, not a second build
    • Write the notes of the first release of an image version from CHANGELOG.md, later releases name the SQLite update
    • Mark the GitHub release that latest points at as the latest release
    • Run every step with bash, so a failing command in a pipe fails the step
    • Queue release runs instead of cancelling them, so no two runs publish or move tags at the same time
  • Remove the SQLITE_UID and SQLITE_GID build arguments, the user is 65532:65532
  • Rename the build argument BUILD_DATE to CREATED, add SOURCE_DATE_EPOCH and require IMAGE_VERSION
  • Bump Alpine in the build stage from 3.24.2 to 3.24.3

Fixed

  • Push nothing but the release index, its images and their attestations, the old release workflow pushed every platform as an index of its own by digest, which stayed behind untagged and unused next to the release index on ghcr.io and docker.io
  • Copy the labels of the image to the annotations of the release index, ghcr.io reads the description and the license of an image of several platforms from there and showed neither
  • List SQLite, tini and BusyBox in the SBOM attestation with their versions, licenses, package URLs and CPEs, from an SBOM document in /var/lib/db/sbom that takes the place of the package database a scratch image lacks
  • Match LICENSE to the AGPL-3.0 text on gnu.org

Refactored

  • Name the final stage of the Dockerfile final

Maintenance

  • Add scripts/clean-manifests.sh and a monthly workflow that delete the manifests no tag needs from ghcr.io and docker.io, such as the untagged images the old release workflow left behind and the images of closed pull requests, and keep every release and every image a tag points at
  • Add scripts/size.sh to measure the compressed and the on-disk size of every platform, and comment the size change of every pull request compared with the latest release
  • Add scripts/build.sh to build the image locally with the image version CI builds with, for the platform of the Docker host or the platforms PLATFORM names
  • Run docker build checks in scripts/lint.sh and stop at the first failed check
  • Stop every script on arguments it does not take
  • Indent JSON with tabs and format Markdown with prettier
  • Bump actions/download-artifact to v8.0.2, actions/upload-artifact to v7.0.2 and docker/login-action to v4.7.0
  • Document the release process in RELEASE.md
  • Describe the image in README.md as a central home for SQLite databases, explain that the application keeps its own SQLite engine, add copying the static sqlite3 shell into other images and drop the uid 65532 note
  • Add reproducible builds, PIE, detached runs and SQLite updates to docs/comparison.md and explain the UPX packing of grepular/sqlite3
  • Put the scope first in SECURITY.md
  • Add a Why section to the pull request template

- the same commit builds the same image digest (the same image, byte for byte)
- the created date is now the commit date
- .recover, .dbinfo and the sqlite_dbpage and sqlite_stmt virtual tables
- run the upstream check twice per day
- add a concurrency group, cache-mode none and a job name
- set bash as the default shell so a failing command in a pipe fails the step
- improve the pull request title and description
- label the pull request with the bot/upstream label
- run the tests on the branch of the pull request
- close open pull requests for older versions when a new one is opened
- add reproducible builds, PIE and detached runs to comparison.md
- change the SQLite version row to SQLite updates, which now says how each image gets a new release
- say where to report a vulnerability in SQLite, BusyBox or tini
- update the example tags to 3.54.1-v0.2.0
- show the amd64 image size in the size badge and switch tests to the release workflow
- describe the image as a central home for SQLite databases in the introduction
- update what makes this image different
- explain that the application still talks to the database through its own SQLite engine, version and extensions, and what this image does next to it
- drop the uid 65532 note and the user line from the Compose example
- add a section on copying the static sqlite3 shell into other images
- update the example tags to 3.54.1-v0.2.0 and add the preview tag
- bump stable.image or preview.image in release.json instead of IMAGE_VERSION in the Dockerfile
- release from main, next, release and maintenance branches
- allow prereleases with an alpha, beta or rc stage
- offer the versions the branch allows and preselect the bump the commits need
- skip a version another branch released and warn about one a release branch holds
- date the CHANGELOG.md entries only for a stable release
- split the build, test and release workflows
- release on a push that changes release.json or src/upstream.json
- select the releases with scripts/version.sh from release.json and src/upstream.json
- build and test every upstream line for every platform
- publish the tested images instead of a second build
- publish the prereleases of next and the release branches as GitHub prereleases
- take the notes of a first release from CHANGELOG.md and publish it right away, not as a draft
- move the tags scripts/version.sh names on both registries and mark the GitHub release of latest
- read the Docker Hub credentials only in jobs of the release environment
- queue release runs instead of cancelling them, so no run is lost and no two runs move tags at once
- run without the GitHub Actions cache, so no run restores a cache another run poisoned
- run every step with bash, so a failing command in a pipe fails the step
- merge forward after a release
- zstd is faster, more modern and compresses better than gzip, pulling needs Docker Engine 23.0 or later
- a scratch image has no package database, sbom.sh writes a syft JSON document into /var/lib/db/sbom for the scanner
- a build without IMAGE_VERSION stops in the build stage
- it runs privileged and installs QEMU of every emulated build
- without --chmod the image takes the modes of the checkout, which follow the umask of whoever cloned it, so a checkout with umask 000 makes /usr/local/bin writable for every user
- the pull request workflow now calls the build workflow, which no longer runs on pull_request
- a pull request from a fork is built but not published
- ghcr.io reads the description and the license of an image of several platforms from the annotations of its index, not from the labels of each image
- the pull request workflow leaves the images of every closed pull request behind on ghcr.io
- docker_hub is undefined for a manifest ghcr.io has, as a HEAD on docker.io for every one of them could trigger rate limits
- ghcr.io lists deleted versions for 30 days, a HEAD on docker.io for each would reach thousands per run, which could trigger rate limits
- twice the count covers the last two runs, and manifests only docker.io has sort first, so a copy docker.io refused is deleted within two runs
- reads the layouts the build workflow built, so no second build is needed to get the pull request image sizes
- only the commits that bump the image or the SQLite version stay ignored, so a feat change to the release process asks for a minor
- next gets one merge per release, named after its tag, and no merge of main commits that are not released yet
- a push that changes release.json or src/upstream.json stays unbuilt as the release workflow builds it
@github-actions

Copy link
Copy Markdown
Contributor

Image size

pr-3 compared with latest (3.54.1-v0.1.0).

Platform Compressed pr-3 Compressed latest Change On disk pr-3 On disk latest Change
linux/386 1.41 MB - - 4.11 MB - -
linux/amd64 1.40 MB 1.52 MB -117.3 kB (-7.7 %) 4.10 MB 4.15 MB -55.8 kB (-1.3 %)
linux/arm/v6 1.42 MB - - 4.29 MB - -
linux/arm/v7 1.32 MB 1.40 MB -76.4 kB (-5.5 %) 3.36 MB 3.39 MB -31.3 kB (-0.9 %)
linux/arm64 1.42 MB 1.58 MB -165.8 kB (-10.5 %) 4.28 MB 4.37 MB -88.0 kB (-2.0 %)
linux/ppc64le 1.50 MB - - 4.75 MB - -
linux/riscv64 1.46 MB 1.58 MB -119.1 kB (-7.5 %) 3.96 MB 4.02 MB -65.9 kB (-1.6 %)
linux/s390x 1.46 MB - - 4.64 MB - -

Compressed is what docker pull downloads, the CONTENT SIZE of the platform in docker image ls --tree. On disk adds the unpacked files in 4 KiB blocks of ext4, the DISK USAGE that Docker Desktop shows, as the containerd image store keeps both. Neither counts the SBOM and provenance attestations.

@peaklabs-dev
peaklabs-dev marked this pull request as ready for review October 30, 2026 16:19
@peaklabs-dev
peaklabs-dev merged commit 32d0d2c into main Oct 30, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant