Pin node images to the checked-out source tree — fix v1 code / :latest image skew (#19) #31
Merged
logan
merged 3 commits from 2026-10-04 18:26:01 -04:00
fix/19-image-tag-skew into main
No Reviewers
Labels
Clear labels
area/ai-pipeline
area/auth
area/billing
area/correlation
area/discord
area/frontend
area/governance
area/growth
area/infra-deploy
area/legal
area/map
area/mqtt
area/node-ota
area/osint
area/recording-audio
area/sdr-radio
area/transcription
board
board:agenda
Scene/entity extraction, summarizer, AI providers, embeddings
AuthN/Z, roles, tenancy/org scoping, API keys, credentials
Plans, entitlements, AI spend accounting and caps
Incident correlation, linking, lifecycle, severity, corr_debug
Discord bot, radio bots, voice streams, bot tokens, webhooks
Web UI: Next.js app and the edge-node local dashboard
Board process, minutes, unattended runner, agent tooling
Go-to-market, outreach, cold email, discovery conversations
CI/CD, VM, registry, Firestore rules/indexes deploy, Terraform/Caddy
ToS, retention, licences/DAAs, CAN-SPAM, E&O, name suppression
Live map: pins, paths, tiles, legend, geocoding
Node-C2 MQTT, checkins, commands, node sweeper, dynsec
Node install, enrollment, OTA updater, image skew
External feeds: cameras, 511, ADS-B, AIS, outages, and their licences
Call capture, boundaries, PulseAudio, ring buffer, trimming, attribution
OP25 decode, SDR hardware/tuning, conventional, second SDR, mesh radio
STT, transcript correction, place verification, name accuracy
Board process: minutes and board-filed items
Needs board scoping at the next sitting; CEO removes the label once scoped
kind
behavior-bug
Wrong product behavior; the instrument reads it correctly
kind
measurement-bug
Corrupts the recording/instrument (debug data, evals, health checks), not behavior
priority
p0
Drop everything: prod broken, live exposure, or owner-ruled P0
priority
p1
Next up: blocks a gate, a customer, or core incident quality
priority
p2
Normal: real defect or planned work, schedule in turn
priority
p3
Low: minor, cosmetic, or someday
status
blocked
Waiting on an external party, spend, or another issue
status
in-progress
Branch or PR open against it
status
needs-decision
Waiting on an owner or board ruling before work
status
needs-info
Root cause or repro unknown; needs a reading first
type
bug
Something built is wrong: code, data, or a measurement
type
chore
Maintenance, refactor, tests, pinning, cleanup: no user-visible change
type
decision
A ruling to make or record: board minutes, owner calls, legal reviews
type
docs
Docs, runbooks, CLAUDE.md, skills, SOPs
type
feature
New capability or an extension of an existing one
type
security
Security, privacy, credential or tenant-isolation exposure
type
tracking
Tracker, checklist, initiative or punch-list spanning several changes
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: logan/node-26#31
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Fixes #19 (install.sh hazard D3).
Problem: nodes check out
v1code and bind-mount it over images tagged:latest/:stable, which CI builds from main. A dependency orop25_addons/tk_drb_conv.pychange on main therefore runs under v1 code without any warning.Fix: pin each image to the source tree it was built from. The tag is
src-<git tree hash of the image's build directory>.build-*.ymladds thesrc-tag.:latest,:stableand the version tag are unchanged, so dev and old nodes keep working.scripts/image-tags.shcomputes the same hash from the checkout (git rev-parse <commit>:<dir>) and writesDRB_TAG_*into.env.docker-compose.ymluses${DRB_TAG_*:-latest|stable}, so manualdocker compose/make up-prebuilton the node use the same pins.install.sh: pins right after checkout. Aftercompose pullit checks that every pinned image is present, because compose only warns when a service with abuild:section fails to pull. If one is missing it stops with a clear message.drb-update.sh: in pull mode it pulls the target commit's pinned images before checking out, using the target's own compose file. A missing image therefore leaves the node untouched. Before, uvicorn--reloadpicked up new code on old images as soon as the checkout landed. After the pull it checks out, writes the pins, recreates the containers and removessrc-tags that are no longer used. Build mode tags its local builds with the same pins.release-images.yml: runs onv*tag pushes and on manual dispatch. For each image it builds and pushessrc-<tree>only if that tag is missing from the registry.Owner rollout. The v1 tag is not moved by this PR.
main. This PR changes none of the four image directories, so main's trees are the same as v1's and everysrc-image a node will ask for gets published. op25 should mostly come from cache.v1onto the merge commit. The tag push runs Release images again, and it skips everything already published.drb-update.sh, which pulls:latestas today. Every update after that is pinned.Out of scope, existing issues: #17 (no signature or digest verification; this pins by tag, not digest) and #28 (images are arm64-only;
release-images.ymlkeepslinux/arm64).Verification:
bash -non all scripts. All workflows and the compose file parse as YAML. I ranimage-tags.shagainst this repo: the tags matchgit rev-parse HEAD:<dir>,.envkeeps mode 0600 and its other keys, and an older commit gives differentsrc-tags. Not verified: the compose runtime and the Gitea Actions runs. There is no docker on the authoring box, so the first real update needs watching. No Python touched. edge-node pytest: 287 passed, 9 skipped. flake8 is clean.🤖 Generated with Claude Code
Review pass (adversarial): pushed
e7b4aefonto this branch.6c8289f:CI / testfailed —test_host_updater.py's stub git/docker didn't model the new pin path, so the two update-path tests broke (they were skipped on the macOS authoring box, noflock, so the reported 287/9-skipped never exerciseddrb-update.sh). Stubs fixed; added tests for pull-before-checkout +.envpins, missing pinned image => node unchanged, pre-pinning target still updates.drb-update.sh:source <(git show ...)reports success even whengit showfails, leaving pin=1 with no functions defined (every later update wedges). Now read into a variable,eval, anddeclare -Fchecks.install.sh: a--refolder than #19 has noscripts/image-tags.sh; it used to die there. Now warns and uses that ref's compose defaults.Local: edge-node pytest 299 passed, 0 skipped (flock shim), flake8 clean.
🤖 Generated with Claude Code