Skip to content

Commit a73ee7b

Browse files
Merge pull request #49 from runtimeverification/add-deploy-script
Add manual deployment script as single source of truth
2 parents da3a6c9 + 0ff68a2 commit a73ee7b

10 files changed

Lines changed: 368 additions & 109 deletions

File tree

.devcontainer/Dockerfile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,18 @@ ENV PATH=/home/vscode/.nix-profile/bin:/home/vscode/.npm-global/bin:$PATH
5959
# - gh → GitHub CLI for PRs/issues/auth; global so it's usable
6060
# from anywhere. Auth is persisted across rebuilds via a
6161
# named volume on ~/.config/gh (see devcontainer.json).
62+
# - cachix → required by scripts/deploy.sh `nix-cache` to push the
63+
# build closure to the k-framework cache. kup (the other
64+
# half of that deploy step) is fetched via nix at run
65+
# time, so only cachix needs provisioning here.
6266
RUN . /home/vscode/.nix-profile/etc/profile.d/nix.sh \
6367
&& nix registry add nixpkgs github:NixOS/nixpkgs/nixos-25.05 \
6468
&& nix profile install \
6569
nixpkgs#direnv \
6670
nixpkgs#nix-direnv \
6771
nixpkgs#nodejs_22 \
68-
nixpkgs#gh
72+
nixpkgs#gh \
73+
nixpkgs#cachix
6974

7075
# Claude Code CLI — installed to a per-user prefix so root isn't required.
7176
RUN . /home/vscode/.nix-profile/etc/profile.d/nix.sh \
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"features": {
3+
"ghcr.io/devcontainers/features/docker-in-docker:2": {
4+
"version": "2.17.0",
5+
"resolved": "ghcr.io/devcontainers/features/docker-in-docker@sha256:25b9f05705ffba7dbe503230ac76081419306f8c8bc88e0ce78c4ecd99a0c78c",
6+
"integrity": "sha256:25b9f05705ffba7dbe503230ac76081419306f8c8bc88e0ce78c4ecd99a0c78c"
7+
}
8+
}
9+
}

.devcontainer/devcontainer.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@
33
"build": {
44
"dockerfile": "Dockerfile"
55
},
6+
// An isolated Docker daemon inside the container, so `scripts/deploy.sh docker`
7+
// can build and push the release image without touching the host's Docker. The
8+
// feature adds the docker CLI, runs dockerd, and puts `vscode` in the docker
9+
// group; it also marks the container privileged, which dockerd requires.
10+
"features": {
11+
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
12+
},
613
"remoteUser": "vscode",
714
"workspaceFolder": "/workspace",
815
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind",

.dockerignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,16 @@ cov-*
1515
result
1616
result-*
1717
state.kore
18+
19+
# Never ship local secrets. The build context is the whole repo, and the
20+
# Dockerfile does `COPY . komet-node`, so any credential file sitting here
21+
# would be baked into a published image layer (a later `rm` does not remove
22+
# it from history). deploy.sh is run by hand with tokens exported, often via a
23+
# direnv `.envrc` or a `.env`, so keep those and any key/token files out.
24+
.envrc
25+
.env
26+
.env.*
27+
*.pem
28+
*.key
29+
*.token
30+
secrets*

.github/scripts/check-cachix-pin.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
set -euo pipefail
33

44
# Verifies that `kup publish` actually pushed AND pinned komet-node in the
5-
# private k-framework-binary cache. Cachix has intermittently dropped the
5+
# k-framework-binary cache. Cachix has intermittently dropped the
66
# `cachix pin` requests kup makes under the hood, so we confirm both the pin
77
# (visible via the pin API) and the narinfo (the pushed store path) before
88
# treating the publish as successful.

.github/workflows/release.yml

Lines changed: 7 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -40,38 +40,16 @@ jobs:
4040
ref: ${{ github.sha }}
4141
fetch-depth: 0
4242

43-
# Build the komet-node derivation once, then push it to both the public
44-
# k-framework cache (full build closure, via `cachix push`) and the
45-
# private k-framework-binary cache (the kup-installable binary, via
46-
# `kup publish`). Both pushes reuse the build output already present in
47-
# this runner's Nix store, so the derivation is never built twice.
43+
# The build-and-publish logic lives in scripts/deploy.sh so CI and manual
44+
# deployments stay in sync (single source of truth). See CONTRIBUTING.md.
4845
- name: 'Build and publish komet-node to both Nix caches'
4946
shell: bash
5047
env:
51-
GC_DONT_GC: '1'
52-
# Enable flakes for every nix invocation in this step (the initial
53-
# build, the kup build, and the builds kup runs internally) so the
54-
# job does not depend on flakes being globally enabled on the runner.
55-
NIX_CONFIG: 'extra-experimental-features = nix-command flakes'
5648
CACHIX_PUBLIC_TOKEN: '${{ secrets.CACHIX_PUBLIC_TOKEN }}'
5749
CACHIX_PRIVATE_KFB_TOKEN: '${{ secrets.CACHIX_PRIVATE_KFB_TOKEN }}'
5850
OWNER_REPO: '${{ github.repository }}'
5951
REV: '${{ github.sha }}'
60-
run: |
61-
KOMET_NODE=$(nix build .#komet-node --no-link --print-out-paths)
62-
DRV=$(nix-store --query --deriver "${KOMET_NODE}")
63-
64-
# Push the full build closure to the public k-framework cache.
65-
export CACHIX_AUTH_TOKEN="${CACHIX_PUBLIC_TOKEN}"
66-
nix-store --query --requisites --include-outputs "${DRV}" | cachix push k-framework
67-
68-
# Publish the binary to the private k-framework-binary cache. kup
69-
# reuses the store paths built above.
70-
export CACHIX_AUTH_TOKEN="${CACHIX_PRIVATE_KFB_TOKEN}"
71-
export PATH="$(nix build github:runtimeverification/kup --no-link --print-out-paths)/bin:$PATH"
72-
kup publish k-framework-binary .#komet-node --keep-days 180
73-
# Cachix has not been responding to 'cachix pin' requests made under the hood by kup. Verify the push and pin manually.
74-
bash .github/scripts/check-cachix-pin.sh
52+
run: ./scripts/deploy.sh nix-cache
7553

7654
- name: 'On failure, delete drafted release'
7755
if: failure()
@@ -96,32 +74,12 @@ jobs:
9674
ref: ${{ github.sha }}
9775
fetch-depth: 0
9876

99-
- name: 'Set environment'
100-
run: |
101-
KOMET_NODE_VERSION=$(cat package/version)
102-
TAG=runtimeverificationinc/komet-node:ubuntu-jammy-${KOMET_NODE_VERSION}
103-
echo "TAG=${TAG}" >> ${GITHUB_ENV}
104-
105-
- name: 'Build Docker image'
106-
run: |
107-
K_VERSION=$(cat deps/k_release)
108-
docker build . --no-cache --tag ${TAG} --build-arg K_VERSION=${K_VERSION}
109-
110-
- name: 'Run Docker image'
111-
run: docker run --rm ${TAG} komet-node --help
112-
113-
- name: 'Push Docker image to Docker Hub'
77+
# Build, smoke-test, and push logic lives in scripts/deploy.sh so CI and
78+
# manual deployments stay in sync (single source of truth). See CONTRIBUTING.md.
79+
- name: 'Build, test, and push Docker image to Docker Hub'
11480
env:
115-
DOCKERHUB_USERNAME: rvdockerhub
11681
DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }}
117-
DOCKERHUB_NAMESPACE: runtimeverificationinc
118-
DOCKERHUB_REPO: komet-node
119-
run: |
120-
# Log in to Docker Hub
121-
echo "${DOCKERHUB_PASSWORD}" | docker login --username "${DOCKERHUB_USERNAME}" --password-stdin
122-
123-
# Push the image
124-
docker image push ${TAG}
82+
run: ./scripts/deploy.sh docker
12583

12684
- name: 'On failure, delete drafted release'
12785
if: failure()

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
__pycache__/
33
.coverage
44
.direnv/
5+
.env
56

67
# Runtime artifacts written by the server / interpreter in the io dir
78
metadata.json

CONTRIBUTING.md

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# Contributing to Komet Node
2+
3+
## Development environment
4+
5+
This repository ships a [devcontainer](.devcontainer/) that provisions the full
6+
toolchain (Nix, the flake's `nix develop` shell, the Claude Code CLI, and the
7+
GitHub CLI). Open the repo in a devcontainer-aware editor and everything below is
8+
available out of the box.
9+
10+
## Using the GitHub CLI (`gh`)
11+
12+
`gh` is preinstalled in the devcontainer for creating pull requests, reviewing
13+
issues, and other GitHub tasks from the terminal.
14+
15+
### Authenticating
16+
17+
Authenticate once with a personal access token:
18+
19+
```bash
20+
gh auth login
21+
```
22+
23+
Choose **GitHub.com****HTTPS****Paste an authentication token** when
24+
prompted, then paste the token you create below.
25+
26+
Your credentials are stored in `~/.config/gh` inside the container, which is
27+
backed by a named volume. This means **your token survives container rebuilds**
28+
you only need to authenticate once, not every time the container is recreated.
29+
30+
To check or reset your authentication at any time:
31+
32+
```bash
33+
gh auth status # show the current login
34+
gh auth logout # remove stored credentials
35+
```
36+
37+
### Creating a token with minimal permissions
38+
39+
Create a **fine-grained** personal access token at **GitHub → Settings → Developer
40+
settings → [Fine-grained personal access tokens](https://github.com/settings/personal-access-tokens/new)**
41+
with the least privilege for your work:
42+
43+
- **Repository access***Only select repositories*`runtimeverification/komet-node`
44+
- **Contents***Read and write*
45+
- **Pull requests***Read and write*
46+
- **Issues***Read and write* (only if you triage issues)
47+
48+
`Metadata → Read` is selected automatically; leave everything else at *No access*.
49+
50+
## Signing commits
51+
52+
To sign commits made with `git`, add an SSH or GPG key of type **Signing key** to
53+
your GitHub account.
54+
55+
> [!WARNING]
56+
> Never place an SSH key registered as an **Authentication key** in the container.
57+
> An authentication key grants full account-wide git access and would bypass the
58+
> minimal permissions of your fine-grained PAT. Use a **signing-only** key here.
59+
60+
## Deploying a release
61+
62+
`scripts/deploy.sh` builds and publishes the komet-node release artifacts. It is
63+
the single source of truth for the deployment steps: the `Release` workflow
64+
(`.github/workflows/release.yml`) invokes its subcommands, and you run the same
65+
subcommands by hand when CI is unavailable.
66+
67+
### What it does
68+
69+
The script has three subcommands:
70+
71+
| Subcommand | Action |
72+
| ----------- | ------ |
73+
| `nix-cache` | Builds `.#komet-node`, pushes the full build closure to the `k-framework` Cachix cache, publishes the kup-installable binary to the `k-framework-binary` cache, then verifies the push and pin. Both caches are public; `binary` is a historical name, not an access level. |
74+
| `docker` | Builds the runtime image from `Dockerfile`, runs `komet-node --help` in it as a smoke test, then pushes it to Docker Hub. |
75+
| `all` | Runs `nix-cache` then `docker`. |
76+
77+
The image tag is `runtimeverificationinc/komet-node:ubuntu-jammy-<version>`,
78+
where `<version>` comes from `package/version`.
79+
80+
### Prerequisites
81+
82+
Both subcommands run from a checkout of the revision you are releasing, with the
83+
following tools on `PATH`:
84+
85+
- `nix-cache` needs `nix` and `cachix`. It fetches `kup` from
86+
`github:runtimeverification/kup` itself, so you do not install kup separately.
87+
- `docker` needs `docker`.
88+
89+
Each subcommand checks its tools up front and exits with a clear message if one
90+
is missing, before starting the build.
91+
92+
The devcontainer provides all of these: `nix` and `cachix` are installed into the
93+
Nix profile, and the docker-in-docker feature supplies `docker`. If you added
94+
these to an existing container, rebuild it ("Dev Containers: Rebuild Container")
95+
so the new tools are present.
96+
97+
Provide the secrets as environment variables. Everything else has a default (see
98+
the `Shared configuration` block in `deploy.sh`), so a normal checkout needs no
99+
further setup.
100+
101+
| Subcommand | Required environment variables |
102+
| ----------- | ------------------------------ |
103+
| `nix-cache` | `CACHIX_PUBLIC_TOKEN`, `CACHIX_PRIVATE_KFB_TOKEN` |
104+
| `docker` | `DOCKERHUB_PASSWORD` |
105+
106+
`OWNER_REPO` and `REV` default to the current checkout's `origin` remote and
107+
`HEAD`. Override them if you are publishing a revision other than the one checked
108+
out. `DOCKERHUB_USERNAME`, `DOCKERHUB_NAMESPACE`, and `DOCKERHUB_REPO` default to
109+
the release account and repository; override them only to publish elsewhere.
110+
111+
Both subcommands refuse to run if the working tree is not clean. CI builds from a
112+
fresh checkout, so a manual build must too: uncommitted changes and untracked
113+
files would otherwise be baked into the published image or flake build without
114+
matching the `REV` they are published under. Commit, stash, or clean the tree
115+
first. `git status --porcelain` ignores `.gitignore`d paths, so runtime artifacts
116+
and dev caches do not count. Set `ALLOW_DIRTY=1` to override the check when you
117+
deliberately want to publish an uncommitted state.
118+
119+
### Manual release while CI is down
120+
121+
The workflow also drafts, cleans up, and finalizes the GitHub release around the
122+
deployment jobs. When you deploy by hand, run those `gh` steps yourself in this
123+
order. `nix-cache` runs once per architecture (the workflow uses an `x86_64` and
124+
an `ARM64` runner), so run it on a machine of each architecture that should be
125+
cached.
126+
127+
```sh
128+
VERSION=v$(cat package/version)
129+
130+
# 1. Draft the release.
131+
gh release create "$VERSION" --draft --title "$VERSION" --target "$(git rev-parse HEAD)"
132+
133+
# 2. Deploy. Export the secrets first (see the table above).
134+
# Run nix-cache once per architecture; docker once.
135+
./scripts/deploy.sh nix-cache
136+
./scripts/deploy.sh docker
137+
138+
# 3. Finalize the release once every deployment has succeeded.
139+
gh release edit "$VERSION" --draft=false
140+
141+
# If a deployment fails, remove the draft instead:
142+
# gh release delete "$VERSION" --yes --cleanup-tag
143+
```

CONTRIBUTOR.md

Lines changed: 0 additions & 58 deletions
This file was deleted.

0 commit comments

Comments
 (0)